diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/services/serializers/json_api.py b/src/agent_toolkit/forestadmin/agent_toolkit/services/serializers/json_api.py index a40a3f645..a8379e6d7 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/services/serializers/json_api.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/services/serializers/json_api.py @@ -28,6 +28,8 @@ class IntOrFloat(fields.Field): def _serialize(self, value, attr, obj, **kwargs): # type: ignore if value is None: return value + if isinstance(value, int) or isinstance(value, float): + return value try: return int(value) except ValueError: @@ -36,6 +38,8 @@ def _serialize(self, value, attr, obj, **kwargs): # type: ignore def _deserialize(self, value, attr, data, **kwargs): # type: ignore if value is None: return value + if isinstance(value, int) or isinstance(value, float): + return value try: return int(value) except ValueError: diff --git a/src/datasource_django/forestadmin/datasource_django/utils/record_serializer.py b/src/datasource_django/forestadmin/datasource_django/utils/record_serializer.py index 1f1c60359..8afceece3 100644 --- a/src/datasource_django/forestadmin/datasource_django/utils/record_serializer.py +++ b/src/datasource_django/forestadmin/datasource_django/utils/record_serializer.py @@ -1,3 +1,6 @@ +from decimal import Decimal +from typing import Any + from django.db.models import Model from forestadmin.datasource_toolkit.interfaces.query.projections import Projection from forestadmin.datasource_toolkit.interfaces.records import RecordsDataAlias @@ -6,7 +9,7 @@ def instance_to_record_data(instance: Model, projection: Projection) -> RecordsDataAlias: record_data = {} for field_name in projection.columns: - record_data[field_name] = getattr(instance, field_name) + record_data[field_name] = serialize_value(getattr(instance, field_name)) for relation_name, subfields in projection.relations.items(): relation = getattr(instance, relation_name, None) @@ -16,3 +19,9 @@ def instance_to_record_data(instance: Model, projection: Projection) -> RecordsD record_data[relation_name] = None return record_data + + +def serialize_value(value: Any): + if isinstance(value, Decimal): + return float(value) + return value diff --git a/src/datasource_django/tests/test_django_collection.py b/src/datasource_django/tests/test_django_collection.py index 2ab313f7d..5d3d50741 100644 --- a/src/datasource_django/tests/test_django_collection.py +++ b/src/datasource_django/tests/test_django_collection.py @@ -140,6 +140,20 @@ async def test_list_should_work_with_null_relations(self): ], ) + async def test_decimal_should_be_correctly_serialized(self): + ret = await self.book_collection.list( + self.mocked_caller, + PaginatedFilter({"condition_tree": ConditionTreeLeaf("name", Operator.EQUAL, "Unknown Book")}), + Projection("id", "name", "price"), + ) + + self.assertEqual( + ret, + [ + {"id": 3, "name": "Unknown Book", "price": 3.45}, + ], + ) + class TestDjangoCollectionCRUDAggregateBase(TestCase): fixtures = ["person.json", "book.json", "rating.json"] diff --git a/src/datasource_django/tests/test_project_datasource/test_app/fixtures/book.json b/src/datasource_django/tests/test_project_datasource/test_app/fixtures/book.json index ef9f2e782..1c3068213 100644 --- a/src/datasource_django/tests/test_project_datasource/test_app/fixtures/book.json +++ b/src/datasource_django/tests/test_project_datasource/test_app/fixtures/book.json @@ -2,16 +2,16 @@ { "model": "test_app.book", "pk": 1, - "fields": { "name": "Foundation", "author": 1 } + "fields": { "name": "Foundation", "author": 1 , "price": 1.23} }, { "model": "test_app.book", "pk": 2, - "fields": { "name": "Harry Potter", "author": 2 } + "fields": { "name": "Harry Potter", "author": 2 , "price": 2.34} }, { "model": "test_app.book", "pk": 3, - "fields": { "name": "Unknown Book", "author": null } + "fields": { "name": "Unknown Book", "author": null , "price": 3.45} } ] diff --git a/src/datasource_django/tests/test_project_datasource/test_app/migrations/0001_initial.py b/src/datasource_django/tests/test_project_datasource/test_app/migrations/0001_initial.py index 7d80c015c..971d7980e 100644 --- a/src/datasource_django/tests/test_project_datasource/test_app/migrations/0001_initial.py +++ b/src/datasource_django/tests/test_project_datasource/test_app/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.7 on 2023-12-20 13:07 +# Generated by Django 4.2.8 on 2024-02-01 13:19 import django.contrib.auth.models import django.db.models.deletion @@ -6,11 +6,12 @@ class Migration(migrations.Migration): + initial = True dependencies = [ - ("contenttypes", "0002_remove_content_type_name"), ("auth", "0012_alter_user_first_name_max_length"), + ("contenttypes", "0002_remove_content_type_name"), ] operations = [ @@ -27,6 +28,7 @@ class Migration(migrations.Migration): ), ), ("name", models.CharField(max_length=254)), + ("price", models.DecimalField(decimal_places=2, max_digits=5)), ], ), migrations.CreateModel( diff --git a/src/datasource_django/tests/test_project_datasource/test_app/models.py b/src/datasource_django/tests/test_project_datasource/test_app/models.py index 4df0c3f41..ad9dcdc27 100644 --- a/src/datasource_django/tests/test_project_datasource/test_app/models.py +++ b/src/datasource_django/tests/test_project_datasource/test_app/models.py @@ -12,6 +12,7 @@ class Meta: class Book(models.Model): name = models.CharField(max_length=254) author = models.ForeignKey("Person", on_delete=models.CASCADE, related_name="books", null=True) + price = models.DecimalField(decimal_places=2, max_digits=5) class Person(models.Model):