From a8fbbc3a14fca814d6163a72452b77fd1c988f72 Mon Sep 17 00:00:00 2001 From: Julien Barreau Date: Fri, 12 Jan 2024 11:18:44 +0100 Subject: [PATCH 1/2] feat(django_5): support django 5 and GeneratedField --- .../datasource_django/utils/model_introspection.py | 8 ++++++++ .../datasource_django/utils/type_converter.py | 9 +++++++++ src/datasource_django/pyproject.toml | 2 +- src/django_agent/pyproject.toml | 2 +- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/datasource_django/forestadmin/datasource_django/utils/model_introspection.py b/src/datasource_django/forestadmin/datasource_django/utils/model_introspection.py index 9ee725af3..d33b3fbce 100644 --- a/src/datasource_django/forestadmin/datasource_django/utils/model_introspection.py +++ b/src/datasource_django/forestadmin/datasource_django/utils/model_introspection.py @@ -28,6 +28,12 @@ ) from forestadmin.datasource_toolkit.interfaces.models.collections import CollectionSchema +try: + # GeneratedField is available since django 5 + from django.db.models import GeneratedField +except ImportError: + GeneratedField = None + class FieldFactory: @staticmethod @@ -42,6 +48,8 @@ def _build_is_read_only(field: Field) -> bool: return isinstance(field, AutoFieldMixin) elif isinstance(field, DateField) or isinstance(field, TimeField): return field.auto_now is True or field.auto_now_add is True + if GeneratedField is not None and isinstance(field, GeneratedField): + return True return False @classmethod diff --git a/src/datasource_django/forestadmin/datasource_django/utils/type_converter.py b/src/datasource_django/forestadmin/datasource_django/utils/type_converter.py index a91dd0e6c..5342dbf1c 100644 --- a/src/datasource_django/forestadmin/datasource_django/utils/type_converter.py +++ b/src/datasource_django/forestadmin/datasource_django/utils/type_converter.py @@ -6,6 +6,12 @@ from forestadmin.datasource_toolkit.interfaces.fields import ColumnAlias, Operator, PrimitiveType from forestadmin.datasource_toolkit.utils.operators import BaseFilterOperator +try: + # GeneratedField is available since django 5 + from django.db.models import GeneratedField +except Exception: + GeneratedField = None + class ConverterException(DjangoDatasourceException): pass @@ -65,6 +71,9 @@ def convert(cls, field: models.Field) -> ColumnAlias: if isinstance(field, models.ForeignKey): return cls.convert(field.target_field) + if GeneratedField is not None and isinstance(field, GeneratedField): + return cls.convert(field.output_field) + if field.__class__ in cls.TYPES: return cls.TYPES[field.__class__] diff --git a/src/datasource_django/pyproject.toml b/src/datasource_django/pyproject.toml index 745d45072..813f8eb9e 100644 --- a/src/datasource_django/pyproject.toml +++ b/src/datasource_django/pyproject.toml @@ -15,7 +15,7 @@ include = "forestadmin" python = ">=3.8,<3.13" typing-extensions = "~=4.2" tzdata = "~=2022.6" -django = ">=3.2,<5.0" +django = ">=3.2,<6.0" psycopg2 = ">=2.8.4" forestadmin-datasource-toolkit = "1.3.0-beta.5" forestadmin-agent-toolkit = "1.3.0-beta.5" diff --git a/src/django_agent/pyproject.toml b/src/django_agent/pyproject.toml index 84b1cb0e3..e8af40402 100644 --- a/src/django_agent/pyproject.toml +++ b/src/django_agent/pyproject.toml @@ -17,7 +17,7 @@ typing-extensions = "~=4.2" tzdata = "~=2022.6" forestadmin-agent-toolkit = "1.3.0-beta.5" forestadmin-datasource-django = "1.3.0-beta.5" -django = ">=3.2,<5.0" +django = ">=3.2,<6.0" django-cors-headers = ">=3.8" [tool.pytest.ini_options] From a6cc000cd4a583b296d1c1f393c1a18ff44bd08e Mon Sep 17 00:00:00 2001 From: Julien Barreau Date: Fri, 12 Jan 2024 11:22:03 +0100 Subject: [PATCH 2/2] chore(django_5): add commented example for GeneratedField in example project --- src/_example/django/django_demo/app/models.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/_example/django/django_demo/app/models.py b/src/_example/django/django_demo/app/models.py index 59f0f4e2a..8308791dd 100644 --- a/src/_example/django/django_demo/app/models.py +++ b/src/_example/django/django_demo/app/models.py @@ -3,6 +3,8 @@ from app.flask_models import * # noqa:F401,F403 from django.db import models +# from django.db.models.functions import Concat + """ checklist: * data types: @@ -61,6 +63,23 @@ class Address(models.Model): country = models.CharField(max_length=254, default="France") zip_code = models.CharField(max_length=5, default="75009") + # test with django 5 ; if enable, don't forget to make migration and migrate + # full_text_address = models.GeneratedField( + # expression=Concat( + # models.F("number"), + # models.Value(" "), + # models.F("street"), + # models.Value(" "), + # models.F("zip_code"), + # models.Value(" "), + # models.F("city"), + # models.Value(" "), + # models.F("country"), + # ), + # output_field=models.TextField(), + # db_persist=False, + # ) + customers = models.ManyToManyField( "Customer", related_name="addresses", through="CustomerAddress", through_fields=("address", "customer") )