def patch(self, request, field_id): """Updates the field if the user belongs to the group.""" field = (FieldHandler().get_field( field_id, base_queryset=Field.objects.select_for_update()).specific) type_name = type_from_data_or_registry(request.data, field_type_registry, field) field_type = field_type_registry.get(type_name) data = validate_data_custom_fields( type_name, field_type_registry, request.data, base_serializer_class=UpdateFieldSerializer, ) # Because each field type can raise custom exceptions at while updating the # field we need to be able to map those to the correct API exceptions which are # defined in the type. with field_type.map_api_exceptions(): field = FieldHandler().update_field(request.user, field, type_name, **data) serializer = field_type_registry.get_serializer(field, FieldSerializer) return Response(serializer.data)
def post(self, request, data, table_id): """Creates a new field for a table.""" type_name = data.pop('type') field_type = field_type_registry.get(type_name) table = TableHandler().get_table(request.user, table_id) # Because each field type can raise custom exceptions while creating the # field we need to be able to map those to the correct API exceptions which are # defined in the type. with field_type.map_api_exceptions(): field = FieldHandler().create_field(request.user, table, type_name, **data) serializer = field_type_registry.get_serializer(field, FieldSerializer) return Response(serializer.data)
def test_list_rows(api_client, data_fixture): user, jwt_token = data_fixture.create_user_and_token(email='*****@*****.**', password='******', first_name='Test1') table = data_fixture.create_database_table(user=user) table_2 = data_fixture.create_database_table() field_1 = data_fixture.create_text_field(name='Name', table=table, primary=True) field_2 = data_fixture.create_number_field(name='Price', table=table) token = TokenHandler().create_token(user, table.database.group, 'Good') wrong_token = TokenHandler().create_token(user, table.database.group, 'Wrong') TokenHandler().update_token_permissions(user, wrong_token, True, False, True, True) model = table.get_model(attribute_names=True) row_1 = model.objects.create(name='Product 1', price=50) row_2 = model.objects.create(name='Product 2/3', price=100) row_3 = model.objects.create(name='Product 3', price=150) row_4 = model.objects.create(name='Last product', price=200) response = api_client.get(reverse('api:database:rows:list', kwargs={'table_id': 999999}), format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') assert response.status_code == HTTP_404_NOT_FOUND assert response.json()['error'] == 'ERROR_TABLE_DOES_NOT_EXIST' response = api_client.get(reverse('api:database:rows:list', kwargs={'table_id': table_2.id}), format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') assert response.status_code == HTTP_400_BAD_REQUEST assert response.json()['error'] == 'ERROR_USER_NOT_IN_GROUP' response = api_client.get(reverse('api:database:rows:list', kwargs={'table_id': table.id}), format='json', HTTP_AUTHORIZATION='Token abc123') assert response.status_code == HTTP_401_UNAUTHORIZED assert response.json()['error'] == 'ERROR_TOKEN_DOES_NOT_EXIST' response = api_client.get(reverse('api:database:rows:list', kwargs={'table_id': table.id}), format='json', HTTP_AUTHORIZATION=f'Token {wrong_token.key}') assert response.status_code == HTTP_401_UNAUTHORIZED assert response.json()['error'] == 'ERROR_NO_PERMISSION_TO_TABLE' response = api_client.get(reverse('api:database:rows:list', kwargs={'table_id': table.id}), format='json', HTTP_AUTHORIZATION=f'Token {token.key}') assert response.status_code == HTTP_200_OK response = api_client.get(reverse('api:database:rows:list', kwargs={'table_id': table.id}), format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json['count'] == 4 assert len(response_json['results']) == 4 assert response_json['results'][0]['id'] == row_1.id assert response_json['results'][0][f'field_{field_1.id}'] == 'Product 1' assert response_json['results'][0][f'field_{field_2.id}'] == 50 url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?size=2&page=1', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json['count'] == 4 assert len(response_json['results']) == 2 assert response_json['results'][0]['id'] == row_1.id assert response_json['results'][1]['id'] == row_2.id url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?size=2&page=2', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json['count'] == 4 assert len(response_json['results']) == 2 assert response_json['results'][0]['id'] == row_3.id assert response_json['results'][1]['id'] == row_4.id url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?size=2&page=3', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_400_BAD_REQUEST assert response_json['error'] == 'ERROR_INVALID_PAGE' url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?size=201', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_400_BAD_REQUEST assert response_json['error'] == 'ERROR_PAGE_SIZE_LIMIT' url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?search=Product 1', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json['count'] == 1 assert len(response_json['results']) == 1 assert response_json['results'][0]['id'] == row_1.id url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?search=1', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json['count'] == 1 assert len(response_json['results']) == 1 assert response_json['results'][0]['id'] == row_1.id url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?search=3', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json['count'] == 2 assert len(response_json['results']) == 2 assert response_json['results'][0]['id'] == row_2.id assert response_json['results'][1]['id'] == row_3.id url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?search=200', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json['count'] == 1 assert len(response_json['results']) == 1 assert response_json['results'][0]['id'] == row_4.id url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?order_by=field_999999', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') assert response.status_code == HTTP_400_BAD_REQUEST response_json = response.json() assert response_json['error'] == 'ERROR_ORDER_BY_FIELD_NOT_FOUND' assert response_json['detail'] == ( 'The field field_999999 was not found in the table.') number_field_type = field_type_registry.get('number') old_can_order_by = number_field_type.can_order_by number_field_type.can_order_by = False url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?order_by=-field_{field_2.id}', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') assert response.status_code == HTTP_400_BAD_REQUEST response_json = response.json() assert response_json['error'] == 'ERROR_ORDER_BY_FIELD_NOT_POSSIBLE' assert response_json['detail'] == ( f'It is not possible to order by field_{field_2.id} because the field type ' f'number does not support filtering.') number_field_type.can_order_by = old_can_order_by url = reverse('api:database:rows:list', kwargs={'table_id': table.id}) response = api_client.get(f'{url}?order_by=-field_{field_2.id}', format='json', HTTP_AUTHORIZATION=f'JWT {jwt_token}') response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json['count'] == 4 assert len(response_json['results']) == 4 assert response_json['results'][0]['id'] == row_4.id assert response_json['results'][1]['id'] == row_3.id assert response_json['results'][2]['id'] == row_2.id assert response_json['results'][3]['id'] == row_1.id
def import_serialized(self, group, serialized_values, id_mapping, files_zip, storage): """ Imports a database application exported by the `export_serialized` method. """ if "database_tables" not in id_mapping: id_mapping["database_tables"] = {} tables = serialized_values.pop("tables") database = super().import_serialized(group, serialized_values, id_mapping, files_zip, storage) connection = connections[settings.USER_TABLE_DATABASE] # First, we want to create all the table instances because it could be that # field or view properties depend on the existence of a table. for table in tables: table_object = Table.objects.create( database=database, name=table["name"], order=table["order"], ) id_mapping["database_tables"][table["id"]] = table_object.id table["_object"] = table_object table["_field_objects"] = [] # Because view properties might depend on fields, we first want to create all # the fields. for table in tables: for field in table["fields"]: field_type = field_type_registry.get(field["type"]) field_object = field_type.import_serialized( table["_object"], field, id_mapping) if field_object: table["_field_objects"].append(field_object) # Now that the all tables and fields exist, we can create the views and create # the table schema in the database. for table in tables: for view in table["views"]: view_type = view_type_registry.get(view["type"]) view_type.import_serialized(table["_object"], view, id_mapping) # We don't need to create all the fields individually because the schema # editor can handle the creation of the table schema in one go. with connection.schema_editor() as schema_editor: model = table["_object"].get_model( fields=table["_field_objects"], field_ids=[]) schema_editor.create_model(model) # Now that everything is in place we can start filling the table with the rows # in an efficient matter by using the bulk_create functionality. for table in tables: model = table["_object"].get_model(fields=table["_field_objects"], field_ids=[]) field_ids = [ field_object.id for field_object in table["_field_objects"] ] rows_to_be_inserted = [] for row in table["rows"]: row_object = model(id=row["id"], order=row["order"]) for field in table["fields"]: field_type = field_type_registry.get(field["type"]) new_field_id = id_mapping["database_fields"][field["id"]] # If the new field id is not present in the field_ids then we don't # want to set that value on the row. This is because upon creation # of the field there could be a deliberate choice not to populate # that field. This is for example the case with the related field # of the `link_row` field which would result in duplicates if we # would populate. if new_field_id in field_ids: field_type.set_import_serialized_value( row_object, f'field_{id_mapping["database_fields"][field["id"]]}', row[f'field_{field["id"]}'], id_mapping, files_zip, storage, ) rows_to_be_inserted.append(row_object) # We want to insert the rows in bulk because there could potentially be # hundreds of thousands of rows in there and this will result in better # performance. model.objects.bulk_create(rows_to_be_inserted) # When the rows are inserted we keep the provide the old ids and because of # that the auto increment is still set at `1`. This needs to be set to the # maximum value because otherwise creating a new row could later fail. connection = connections[settings.USER_TABLE_DATABASE] sequence_sql = connection.ops.sequence_reset_sql( no_style(), [model]) with connection.cursor() as cursor: cursor.execute(sequence_sql[0]) return database
def test_can_convert_between_all_fields(data_fixture): """ A nuclear option test turned off by default to help verify changes made to field conversions work in every possible conversion scenario. This test checks is possible to convert from every possible field to every other possible field including converting to themselves. It only checks that the conversion does not raise any exceptions. """ user = data_fixture.create_user() database = data_fixture.create_database_application(user=user) table = data_fixture.create_database_table(database=database, user=user) link_table = data_fixture.create_database_table(database=database, user=user) data_fixture.create_text_field(table=link_table, name="text_field", primary=True) handler = FieldHandler() row_handler = RowHandler() fake = Faker() model = table.get_model() cache = {} # Make a blank row to test empty field conversion also. model.objects.create(**{}) second_row_with_values = model.objects.create(**{}) # Some baserow field types have multiple different 'modes' which result in # different conversion behaviour or entirely different database columns being # created. Here the kwargs which control these modes are enumerated so we can then # generate every possible type of conversion. all_possible_kwargs_per_type = construct_all_possible_field_kwargs( link_table) i = 1 for field_type_name, all_possible_kwargs in all_possible_kwargs_per_type.items( ): for kwargs in all_possible_kwargs: for inner_field_type_name in field_type_registry.get_types(): for inner_kwargs in all_possible_kwargs_per_type[ inner_field_type_name]: field_type = field_type_registry.get(field_type_name) from_field = handler.create_field( user=user, table=table, type_name=field_type_name, **kwargs, ) random_value = field_type.random_value( from_field, fake, cache) if isinstance(random_value, date): # Faker produces subtypes of date / datetime which baserow # does not want, instead just convert to str. random_value = str(random_value) row_handler.update_row( user=user, table=table, row_id=second_row_with_values.id, values={f"field_{from_field.id}": random_value}, ) handler.update_field( user=user, field=from_field, new_type_name=inner_field_type_name, **inner_kwargs, ) i = i + 1
def test_list_rows(api_client, data_fixture): user, jwt_token = data_fixture.create_user_and_token(email="*****@*****.**", password="******", first_name="Test1") table = data_fixture.create_database_table(user=user) table_2 = data_fixture.create_database_table() field_1 = data_fixture.create_text_field(name="Name", table=table, primary=True) field_2 = data_fixture.create_number_field(name="Price", table=table) field_3 = data_fixture.create_text_field() field_4 = data_fixture.create_boolean_field(name="InStock", table=table) token = TokenHandler().create_token(user, table.database.group, "Good") wrong_token = TokenHandler().create_token(user, table.database.group, "Wrong") TokenHandler().update_token_permissions(user, wrong_token, True, False, True, True) model = table.get_model(attribute_names=True) row_1 = model.objects.create(name="Product 1", price=50, order=Decimal("1")) row_2 = model.objects.create(name="Product 2/3", price=100, order=Decimal("2")) row_3 = model.objects.create(name="Product 3", price=150, order=Decimal("3")) row_4 = model.objects.create(name="Last product", price=200, order=Decimal("4")) response = api_client.get( reverse("api:database:rows:list", kwargs={"table_id": 999999}), format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) assert response.status_code == HTTP_404_NOT_FOUND assert response.json()["error"] == "ERROR_TABLE_DOES_NOT_EXIST" response = api_client.get( reverse("api:database:rows:list", kwargs={"table_id": table_2.id}), format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) assert response.status_code == HTTP_400_BAD_REQUEST assert response.json()["error"] == "ERROR_USER_NOT_IN_GROUP" response = api_client.get( reverse("api:database:rows:list", kwargs={"table_id": table.id}), format="json", HTTP_AUTHORIZATION="Token abc123", ) assert response.status_code == HTTP_401_UNAUTHORIZED assert response.json()["error"] == "ERROR_TOKEN_DOES_NOT_EXIST" response = api_client.get( reverse("api:database:rows:list", kwargs={"table_id": table.id}), format="json", HTTP_AUTHORIZATION=f"Token {wrong_token.key}", ) assert response.status_code == HTTP_401_UNAUTHORIZED assert response.json()["error"] == "ERROR_NO_PERMISSION_TO_TABLE" user.is_active = False user.save() response = api_client.get( reverse("api:database:rows:list", kwargs={"table_id": table.id}), format="json", HTTP_AUTHORIZATION=f"Token {token.key}", ) assert response.status_code == HTTP_401_UNAUTHORIZED assert response.json()["error"] == "ERROR_USER_NOT_ACTIVE" user.is_active = True user.save() response = api_client.get( reverse("api:database:rows:list", kwargs={"table_id": table.id}), format="json", HTTP_AUTHORIZATION=f"Token {token.key}", ) assert response.status_code == HTTP_200_OK response = api_client.get( reverse("api:database:rows:list", kwargs={"table_id": table.id}), format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 4 assert len(response_json["results"]) == 4 assert response_json["results"][0]["id"] == row_1.id assert response_json["results"][0][f"field_{field_1.id}"] == "Product 1" assert response_json["results"][0][f"field_{field_2.id}"] == "50" assert response_json["results"][0]["order"] == "1.00000000000000000000" url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get( f"{url}?include=field_{field_1.id},field_{field_3.id}", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_200_OK assert f"field_{field_1.id}" in response_json["results"][0] assert f"field_{field_2.id}" not in response_json["results"][0] assert f"field_{field_3.id}" not in response_json["results"][0] url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get( f"{url}?exclude=field_{field_1.id}", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_200_OK assert f"field_{field_1.id}" not in response_json["results"][0] assert f"field_{field_2.id}" in response_json["results"][0] url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get(f"{url}?size=2&page=1", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}") response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 4 assert len(response_json["results"]) == 2 assert response_json["results"][0]["id"] == row_1.id assert response_json["results"][1]["id"] == row_2.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get(f"{url}?size=2&page=2", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}") response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 4 assert len(response_json["results"]) == 2 assert response_json["results"][0]["id"] == row_3.id assert response_json["results"][1]["id"] == row_4.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get(f"{url}?size=2&page=3", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}") response_json = response.json() assert response.status_code == HTTP_400_BAD_REQUEST assert response_json["error"] == "ERROR_INVALID_PAGE" url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get(f"{url}?size=201", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}") response_json = response.json() assert response.status_code == HTTP_400_BAD_REQUEST assert response_json["error"] == "ERROR_PAGE_SIZE_LIMIT" url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get(f"{url}?search=Product 1", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}") response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 1 assert len(response_json["results"]) == 1 assert response_json["results"][0]["id"] == row_1.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get(f"{url}?search=4", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}") response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 1 assert len(response_json["results"]) == 1 assert response_json["results"][0]["id"] == row_4.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get(f"{url}?search=3", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}") response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 2 assert len(response_json["results"]) == 2 assert response_json["results"][0]["id"] == row_2.id assert response_json["results"][1]["id"] == row_3.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get(f"{url}?search=200", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}") response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 1 assert len(response_json["results"]) == 1 assert response_json["results"][0]["id"] == row_4.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get( f"{url}?order_by=field_999999", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) assert response.status_code == HTTP_400_BAD_REQUEST response_json = response.json() assert response_json["error"] == "ERROR_ORDER_BY_FIELD_NOT_FOUND" assert response_json["detail"] == ( "The field field_999999 was not found in the table.") number_field_type = field_type_registry.get("number") old_can_order_by = number_field_type.can_order_by number_field_type.can_order_by = False url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get( f"{url}?order_by=-field_{field_2.id}", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) assert response.status_code == HTTP_400_BAD_REQUEST response_json = response.json() assert response_json["error"] == "ERROR_ORDER_BY_FIELD_NOT_POSSIBLE" assert response_json["detail"] == ( f"It is not possible to order by field_{field_2.id} because the field type " f"number does not support filtering.") number_field_type.can_order_by = old_can_order_by url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) response = api_client.get( f"{url}?order_by=-field_{field_2.id}", format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 4 assert len(response_json["results"]) == 4 assert response_json["results"][0]["id"] == row_4.id assert response_json["results"][1]["id"] == row_3.id assert response_json["results"][2]["id"] == row_2.id assert response_json["results"][3]["id"] == row_1.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) get_params = [f"filter__field_9999999__contains=last"] response = api_client.get( f'{url}?{"&".join(get_params)}', format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_400_BAD_REQUEST assert response_json["error"] == "ERROR_FILTER_FIELD_NOT_FOUND" url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) get_params = [f"filter__field_{field_4.id}__contains=100"] response = api_client.get( f'{url}?{"&".join(get_params)}', format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_400_BAD_REQUEST assert response_json["error"] == "ERROR_VIEW_FILTER_TYPE_UNSUPPORTED_FIELD" url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) get_params = [f"filter__field_{field_2.id}__INVALID=100"] response = api_client.get( f'{url}?{"&".join(get_params)}', format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_400_BAD_REQUEST assert response_json["error"] == "ERROR_VIEW_FILTER_TYPE_DOES_NOT_EXIST" assert response_json[ "detail"] == "The view filter type INVALID doesn't exist." url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) get_params = [ f"filter__field_{field_1.id}__contains=last", f"filter__field_{field_2.id}__equal=200", ] response = api_client.get( f'{url}?{"&".join(get_params)}', format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 1 assert len(response_json["results"]) == 1 assert response_json["results"][0]["id"] == row_4.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) get_params = [ f"filter__field_{field_1.id}__contains=last", f"filter__field_{field_2.id}__higher_than=110", "filter_type=or", ] response = api_client.get( f'{url}?{"&".join(get_params)}', format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 2 assert len(response_json["results"]) == 2 assert response_json["results"][0]["id"] == row_3.id assert response_json["results"][1]["id"] == row_4.id url = reverse("api:database:rows:list", kwargs={"table_id": table.id}) get_params = [ f"filter__field_{field_1.id}__equal=Product 1", f"filter__field_{field_1.id}__equal=Product 3", "filter_type=or", ] response = api_client.get( f'{url}?{"&".join(get_params)}', format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 2 assert len(response_json["results"]) == 2 assert response_json["results"][0]["id"] == row_1.id assert response_json["results"][1]["id"] == row_3.id row_2.order = Decimal("999") row_2.save() response = api_client.get( reverse("api:database:rows:list", kwargs={"table_id": table.id}), format="json", HTTP_AUTHORIZATION=f"JWT {jwt_token}", ) response_json = response.json() assert response.status_code == HTTP_200_OK assert response_json["count"] == 4 assert len(response_json["results"]) == 4 assert response_json["results"][0]["id"] == row_1.id assert response_json["results"][1]["id"] == row_3.id assert response_json["results"][2]["id"] == row_4.id assert response_json["results"][3]["id"] == row_2.id