From 829f50f0d0ec28ba2b8ec6a38108e048d2082d54 Mon Sep 17 00:00:00 2001 From: Joel-Luca Date: Wed, 26 Nov 2025 11:50:38 +0100 Subject: [PATCH] wip --- CHANGELOG.md | 78 ------------------- README.md | 10 +++ app/management/commands/create_dummy_data.py | 5 +- app/models/__init__.py | 10 ++- app/models/custom_field.py | 15 ++++ app/settings/base.py | 2 + app/tests/custom_fields/factories.py | 21 ----- .../test_custom_field_base_class.py | 33 ++++++++ .../test_custom_field_base_manager.py | 4 +- .../test_custom_field_base_model.py | 8 +- ...test_custom_field_model_base_serializer.py | 4 +- .../test_custom_field_serializer.py | 4 +- .../test_custom_field_viewset.py | 2 +- .../test_system_message_viewset.py | 4 +- app/tests/test_mapping_serializer.py | 4 +- app/tests/test_model_field_mapping.py | 6 +- app/web/__init__.py | 0 app/web/publishable.py | 14 ++++ changes/TI-2890.other | 1 + django_features/custom_fields/__init__.py | 23 ++++++ django_features/custom_fields/admin.py | 3 +- django_features/custom_fields/factories.py | 72 +++++++++++++++++ django_features/custom_fields/models/field.py | 20 +++++ django_features/custom_fields/models/value.py | 5 +- django_features/custom_fields/serializers.py | 5 +- django_features/custom_fields/viewsets.py | 3 +- django_features/settings/__init__.py | 5 ++ .../system_message/factories.py | 6 +- 28 files changed, 237 insertions(+), 130 deletions(-) create mode 100644 app/models/custom_field.py delete mode 100644 app/tests/custom_fields/factories.py create mode 100644 app/tests/custom_fields/test_custom_field_base_class.py create mode 100644 app/web/__init__.py create mode 100644 app/web/publishable.py create mode 100644 changes/TI-2890.other create mode 100644 django_features/custom_fields/factories.py rename {app/tests => django_features}/system_message/factories.py (76%) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd8be44..295cef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,18 +31,6 @@ Bug fixes: - Fixes AttributeError when overriding the init function of the CustomFieldBaseModelSerializer because of the params. (`TI-2994 `_) -2025.5.12 (2025-10-27) ----------------------- - -No changes. - - -2025.5.11 (2025-10-27) ----------------------- - -No changes. - - 2025.5.10 (2025-10-27) ---------------------- @@ -51,18 +39,6 @@ Bug fixes: - Array custom fields get annotated correctly. -2025.5.9 (2025-10-24) ---------------------- - -No changes. - - -2025.8.0 (2025-10-24) ---------------------- - -No changes. - - 2025.5.8 (2025-10-24) --------------------- @@ -79,36 +55,6 @@ Bug fixes: - Handle None values when setting custom values. (`master `_) -2025.5.5 (2025-10-23) ---------------------- - -No changes. - - -2025.5.4 (2025-10-23) ---------------------- - -No changes. - - -2025.5.3 (2025-10-23) ---------------------- - -No changes. - - -2025.5.2 (2025-10-23) ---------------------- - -No changes. - - -2025.5.1 (2025-10-23) ---------------------- - -No changes. - - 2025.5.0 (2025-10-23) --------------------- @@ -117,30 +63,6 @@ Other changes: - Improve MappingSerializer and add option for more related fields. (`TI-2893 `_) -2025.4.3 (2025-10-22) ---------------------- - -No changes. - - -2025.3.0 (2025-10-22) ---------------------- - -No changes. - - -2025.4.2 (2025-10-22) ---------------------- - -No changes. - - -2025.4.1 (2025-10-22) ---------------------- - -No changes. - - 2025.4.0 (2025-10-22) --------------------- diff --git a/README.md b/README.md index 4416e2d..625f6d1 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,16 @@ Your querysets should inherit from `django_features.custom_fields.models.CustomF Your serializers should inherit from `django_features.custom_fields.serializers.CustomFieldBaseModelSerializer`. +#### Base classes + +It is possible to create a base class for the CustomField model and extend it with more attributes and functions: + +`CUSTOM_FIELD_BASE_MODEL_CLASS = "example_app.models.CustomFieldBaseModelClass"` + +It is possible to create a base class for the CustomFieldQuerSet and extend it with more attributes and functions: + +`CUSTOM_FIELD_BASE_QUERYSET_CLASS = "example_app.models.CustomFieldBaseQuerySet"` + ### System Message If you want to use `django_features.system_message`, your base configuration class should inherit from `django_features.system_message.settings.SystemMessageConfigurationMixin`. diff --git a/app/management/commands/create_dummy_data.py b/app/management/commands/create_dummy_data.py index bfe07ff..460aa53 100644 --- a/app/management/commands/create_dummy_data.py +++ b/app/management/commands/create_dummy_data.py @@ -5,6 +5,7 @@ from django.core.management import BaseCommand from app.models import Person +from django_features.custom_fields import get_custom_field_model from django_features.custom_fields.models import CustomField from django_features.custom_fields.models import CustomValue @@ -42,7 +43,7 @@ def handle(self, *args: Any, **options: Any) -> None: print("Add custom fields") for i in range(self.NUMBER_OF_CUSTOM_FIELDS): custom_fields.append( - CustomField( + get_custom_field_model()( content_type=person_c, field_type=CustomField.TYPE_CHOICES[field_type][0], identifier=f"custom_field_{i}", @@ -64,7 +65,7 @@ def handle(self, *args: Any, **options: Any) -> None: ) print("Execute bulk create") - CustomField.objects.bulk_create(custom_fields) + get_custom_field_model().objects.bulk_create(custom_fields) CustomValue.objects.bulk_create(custom_values) Person.objects.bulk_create(objects) diff --git a/app/models/__init__.py b/app/models/__init__.py index 343c5e3..8ee7af6 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -1,6 +1,14 @@ -__all__ = ["Address", "ElectionDistrict", "Municipality", "Person", "PersonType"] +__all__ = [ + "Address", + "ElectionDistrict", + "ExtendedCustomField", + "Municipality", + "Person", + "PersonType", +] from .address import Address +from .custom_field import ExtendedCustomField from .election_distinct import ElectionDistrict from .municipality import Municipality from .person import Person diff --git a/app/models/custom_field.py b/app/models/custom_field.py new file mode 100644 index 0000000..6c44362 --- /dev/null +++ b/app/models/custom_field.py @@ -0,0 +1,15 @@ +from app.web.publishable import PublishableModel +from app.web.publishable import PublishableQuerySet +from django_features.custom_fields.models import CustomField +from django_features.custom_fields.models.field import CustomFieldQuerySet + + +class ExtendedCustomFieldQuerySet(CustomFieldQuerySet, PublishableQuerySet): + pass + + +class ExtendedCustomField(CustomField, PublishableModel): + objects = ExtendedCustomFieldQuerySet.as_manager() + + class Meta(CustomField.Meta): + pass diff --git a/app/settings/base.py b/app/settings/base.py index b8afa09..b6163b3 100644 --- a/app/settings/base.py +++ b/app/settings/base.py @@ -159,4 +159,6 @@ def CONSTANCE_CONFIG_FIELDSETS(self) -> dict: }, } + CUSTOM_FIELD_MODEL = "app.ExtendedCustomField" + SECRET_KEY = values.SecretValue() diff --git a/app/tests/custom_fields/factories.py b/app/tests/custom_fields/factories.py deleted file mode 100644 index 16df6cb..0000000 --- a/app/tests/custom_fields/factories.py +++ /dev/null @@ -1,21 +0,0 @@ -from factory import SubFactory # type: ignore - -from app.tests.system_message.factories import BaseFactory # type: ignore -from django_features.custom_fields import models - - -class CustomFieldFactory(BaseFactory): - class Meta: - model = models.CustomField - - field_type = models.CustomField.FIELD_TYPES.CHAR - identifier = "custom_field" - label_de = "Custom Field Label" - - -class CustomValueFactory(BaseFactory): - class Meta: - model = models.CustomValue - - field = SubFactory(CustomFieldFactory) # type: ignore - value = "custom value" diff --git a/app/tests/custom_fields/test_custom_field_base_class.py b/app/tests/custom_fields/test_custom_field_base_class.py new file mode 100644 index 0000000..c80cfac --- /dev/null +++ b/app/tests/custom_fields/test_custom_field_base_class.py @@ -0,0 +1,33 @@ +from django.db.models import QuerySet +from django_extensions.db.models import TimeStampedModel + +from app.tests import APITestCase +from app.web.publishable import PublishableModel +from app.web.publishable import PublishableQuerySet +from django_features.custom_fields import models +from django_features.custom_fields.factories import CustomFieldFactory +from django_features.custom_fields.models.field import CustomFieldQuerySet + + +class CustomFieldBaseClassTestCase(APITestCase): + def test_custom_field_base_model_class(self) -> None: + self.assertTrue(issubclass(models.CustomField, TimeStampedModel)) + self.assertTrue(issubclass(models.CustomField, PublishableModel)) + + def test_edit_custom_field_base_model_class_field(self) -> None: + custom_field: models.CustomField = CustomFieldFactory() # type: ignore + self.assertFalse(custom_field.is_public) + custom_field.is_public = True + self.assertTrue(custom_field.is_public) + + def test_custom_field_base_queryset_class(self) -> None: + self.assertTrue(issubclass(CustomFieldQuerySet, QuerySet)) + self.assertTrue(issubclass(CustomFieldQuerySet, PublishableQuerySet)) + + def test_publishable_custom_field_base_queryset_class(self) -> None: + CustomFieldFactory(identifier="field_1") + CustomFieldFactory(identifier="field_2", is_public=True) + CustomFieldFactory(identifier="field_3", is_public=True) + self.assertEqual(3, models.CustomField.objects.all().count()) + self.assertEqual(2, models.CustomField.objects.publishable().count()) + self.assertEqual(1, models.CustomField.objects.filter(is_public=False).count()) diff --git a/app/tests/custom_fields/test_custom_field_base_manager.py b/app/tests/custom_fields/test_custom_field_base_manager.py index 7aef821..2129f80 100644 --- a/app/tests/custom_fields/test_custom_field_base_manager.py +++ b/app/tests/custom_fields/test_custom_field_base_manager.py @@ -7,10 +7,10 @@ from app.models import Person from app.models import PersonType from app.tests import APITestCase -from app.tests.custom_fields.factories import CustomFieldFactory -from app.tests.custom_fields.factories import CustomValueFactory from app.tests.factories import PersonFactory from app.tests.factories import PersonTypeFactory +from django_features.custom_fields.factories import CustomFieldFactory +from django_features.custom_fields.factories import CustomValueFactory from django_features.custom_fields.models import CustomField diff --git a/app/tests/custom_fields/test_custom_field_base_model.py b/app/tests/custom_fields/test_custom_field_base_model.py index 2dd0920..5ab5bf5 100644 --- a/app/tests/custom_fields/test_custom_field_base_model.py +++ b/app/tests/custom_fields/test_custom_field_base_model.py @@ -7,10 +7,10 @@ from app.models import Person from app.models import PersonType from app.tests import APITestCase -from app.tests.custom_fields.factories import CustomFieldFactory -from app.tests.custom_fields.factories import CustomValueFactory from app.tests.factories import PersonFactory from app.tests.factories import PersonTypeFactory +from django_features.custom_fields.factories import CustomFieldFactory +from django_features.custom_fields.factories import CustomValueFactory from django_features.custom_fields.models import CustomField from django_features.custom_fields.models import CustomValue @@ -28,7 +28,7 @@ def test_custom_field_base_model_custom_field_type_model(self) -> None: self.assertEqual(PersonType, Person.objects.get_type_model()) def test_custom_field_base_model_set_char_value(self) -> None: - CustomFieldFactory( + CustomFieldFactory( # type: ignore identifier="char_value", content_type=self.person_ct, field_type=CustomField.FIELD_TYPES.CHAR, @@ -54,7 +54,7 @@ def test_custom_field_base_model_set_char_value(self) -> None: self.assertEqual("Char value", CustomValue.objects.first().value) def test_custom_field_base_model_set_text_value(self) -> None: - CustomFieldFactory( + CustomFieldFactory( # type: ignore identifier="text_value", content_type=self.person_ct, field_type=CustomField.FIELD_TYPES.TEXT, diff --git a/app/tests/custom_fields/test_custom_field_model_base_serializer.py b/app/tests/custom_fields/test_custom_field_model_base_serializer.py index 5937656..61c8b2b 100644 --- a/app/tests/custom_fields/test_custom_field_model_base_serializer.py +++ b/app/tests/custom_fields/test_custom_field_model_base_serializer.py @@ -8,9 +8,9 @@ from app.models import Person from app.serializers.person import PersonSerializer from app.tests import APITestCase -from app.tests.custom_fields.factories import CustomFieldFactory -from app.tests.custom_fields.factories import CustomValueFactory from app.tests.factories import PersonFactory +from django_features.custom_fields.factories import CustomFieldFactory +from django_features.custom_fields.factories import CustomValueFactory from django_features.custom_fields.models import CustomField from django_features.custom_fields.models import CustomValue diff --git a/app/tests/custom_fields/test_custom_field_serializer.py b/app/tests/custom_fields/test_custom_field_serializer.py index 63762cf..3eea233 100644 --- a/app/tests/custom_fields/test_custom_field_serializer.py +++ b/app/tests/custom_fields/test_custom_field_serializer.py @@ -4,8 +4,8 @@ from app.models import Person from app.tests import APITestCase -from app.tests.custom_fields.factories import CustomFieldFactory -from app.tests.custom_fields.factories import CustomValueFactory +from django_features.custom_fields.factories import CustomFieldFactory +from django_features.custom_fields.factories import CustomValueFactory from django_features.custom_fields.models import CustomField from django_features.custom_fields.serializers import CustomFieldSerializer diff --git a/app/tests/custom_fields/test_custom_field_viewset.py b/app/tests/custom_fields/test_custom_field_viewset.py index 8917500..37d6992 100644 --- a/app/tests/custom_fields/test_custom_field_viewset.py +++ b/app/tests/custom_fields/test_custom_field_viewset.py @@ -4,7 +4,7 @@ from app.models import Address from app.models import Person from app.tests import APITestCase -from app.tests.custom_fields.factories import CustomFieldFactory +from django_features.custom_fields.factories import CustomFieldFactory class CustomFieldViewSetTest(APITestCase): diff --git a/app/tests/system_message/test_system_message_viewset.py b/app/tests/system_message/test_system_message_viewset.py index 1e566ea..336be0f 100644 --- a/app/tests/system_message/test_system_message_viewset.py +++ b/app/tests/system_message/test_system_message_viewset.py @@ -7,8 +7,8 @@ from pluck import pluck from app.tests import APITestCase -from app.tests.system_message.factories import SystemMessageFactory -from app.tests.system_message.factories import SystemMessageTypeFactory +from django_features.system_message.factories import SystemMessageFactory +from django_features.system_message.factories import SystemMessageTypeFactory class SystemInfoViewSetTest(APITestCase): diff --git a/app/tests/test_mapping_serializer.py b/app/tests/test_mapping_serializer.py index f6aacfd..813a8e6 100644 --- a/app/tests/test_mapping_serializer.py +++ b/app/tests/test_mapping_serializer.py @@ -10,11 +10,11 @@ from app.models import Person from app.serializers.person import PersonMappingSerializer from app.tests import APITestCase -from app.tests.custom_fields.factories import CustomFieldFactory -from app.tests.custom_fields.factories import CustomValueFactory from app.tests.factories import AddressFactory from app.tests.factories import ElectionDistrictFactory from app.tests.factories import PersonFactory +from django_features.custom_fields.factories import CustomFieldFactory +from django_features.custom_fields.factories import CustomValueFactory from django_features.custom_fields.models import CustomField from django_features.custom_fields.models import CustomValue diff --git a/app/tests/test_model_field_mapping.py b/app/tests/test_model_field_mapping.py index c0f92e7..d72127b 100644 --- a/app/tests/test_model_field_mapping.py +++ b/app/tests/test_model_field_mapping.py @@ -4,7 +4,7 @@ from app.models import Address from app.models import Person from app.tests import APITestCase -from app.tests.custom_fields.factories import CustomFieldFactory +from django_features.custom_fields.factories import CustomFieldFactory from django_features.custom_fields.models import CustomField from django_features.settings.fields import ModelFieldMapping @@ -13,12 +13,12 @@ class ModelFieldMappingTestCase(APITestCase): def setUp(self) -> None: self.person_ct = ContentType.objects.get_for_model(Person) self.address_ct = ContentType.objects.get_for_model(Address) - CustomFieldFactory( + CustomFieldFactory( # type: ignore identifier="person_custom_field", content_type=self.person_ct, field_type=CustomField.FIELD_TYPES.CHAR, ) - CustomFieldFactory( + CustomFieldFactory( # type: ignore identifier="address_custom_field", content_type=self.address_ct, field_type=CustomField.FIELD_TYPES.CHAR, diff --git a/app/web/__init__.py b/app/web/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/web/publishable.py b/app/web/publishable.py new file mode 100644 index 0000000..57b3700 --- /dev/null +++ b/app/web/publishable.py @@ -0,0 +1,14 @@ +from django.db import models +from django_extensions.db.models import TimeStampedModel + + +class PublishableQuerySet(models.QuerySet): + def publishable(self) -> "PublishableQuerySet": + return self.filter(is_public=True) + + +class PublishableModel(TimeStampedModel): + is_public = models.BooleanField(default=False) + + class Meta: + abstract = True diff --git a/changes/TI-2890.other b/changes/TI-2890.other new file mode 100644 index 0000000..99c5994 --- /dev/null +++ b/changes/TI-2890.other @@ -0,0 +1 @@ +Add the possibility to configure the base class of the CustomField model and the CustomFieldQuerySet. [TI-2890](https://4teamwork.atlassian.net/browse/TI-2890>) diff --git a/django_features/custom_fields/__init__.py b/django_features/custom_fields/__init__.py index e69de29..21b2d13 100644 --- a/django_features/custom_fields/__init__.py +++ b/django_features/custom_fields/__init__.py @@ -0,0 +1,23 @@ +from typing import Any + +from django.apps import apps as django_apps +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured + + +def get_custom_field_model() -> Any: + """ + Return the CustomField model that is active in this project. + """ + try: + return django_apps.get_model(settings.CUSTOM_FIELD_MODEL, require_ready=False) + except ValueError: + raise ImproperlyConfigured( + f"CUSTOM_FIELD_MODEL must be of the form 'app_label.model_name', given: %s" + % settings.CUSTOM_FIELD_MODEL + ) + except LookupError: + raise ImproperlyConfigured( + "CUSTOM_FIELD_MODEL refers to model '%s' that has not been installed" + % settings.CUSTOM_FIELD_MODEL + ) diff --git a/django_features/custom_fields/admin.py b/django_features/custom_fields/admin.py index 5a35aac..915eee4 100644 --- a/django_features/custom_fields/admin.py +++ b/django_features/custom_fields/admin.py @@ -6,6 +6,7 @@ from django.http import HttpRequest from modeltranslation.admin import TranslationAdmin +from django_features.custom_fields import get_custom_field_model from django_features.custom_fields import models from django_features.custom_fields.models import CustomFieldBaseModel from django_features.custom_fields.models import CustomFieldTypeBaseModel @@ -41,7 +42,7 @@ def get_readonly_fields(self, request: HttpRequest, obj: Any = None) -> list[str return self.readonly_fields -@admin.register(models.CustomField) +@admin.register(get_custom_field_model()) class CustomFieldAdmin(CustomFieldBaseAdmin): list_display = ["id", "identifier", "__str__", "field_type", "filterable"] list_display_links = ( diff --git a/django_features/custom_fields/factories.py b/django_features/custom_fields/factories.py new file mode 100644 index 0000000..ce9399d --- /dev/null +++ b/django_features/custom_fields/factories.py @@ -0,0 +1,72 @@ +from django.contrib.contenttypes.models import ContentType +from factory import lazy_attribute # type: ignore +from factory import SubFactory # type: ignore +from factory.django import DjangoModelFactory + +from app.models import Person +from django_features.custom_fields import get_custom_field_model +from django_features.custom_fields import models + + +class CustomFieldFactory(DjangoModelFactory): + class Meta: + model = get_custom_field_model() + + @lazy_attribute + def content_type(self) -> ContentType: + return ContentType.objects.get_for_model(Person) + + field_type = models.CustomField.FIELD_TYPES.CHAR + identifier = "custom_field" + label_de = "Custom Field Label" + + +class CustomValueFactory(DjangoModelFactory): + class Meta: + model = models.CustomValue + + field = SubFactory(CustomFieldFactory) # type: ignore + value = "custom value" + + +class CustomChoiceFactory(DjangoModelFactory): + class Meta: + model = models.CustomValue + + label_de = "Red" + value = "red" + + +class CustomTextValueFactory(DjangoModelFactory): + class Meta: + model = models.CustomValue + + value = "Custom text" + + +class CustomDateValueFactory(DjangoModelFactory): + class Meta: + model = models.CustomValue + + value = "2019-01-01" + + +class CustomIntegerValueFactory(DjangoModelFactory): + class Meta: + model = models.CustomValue + + value = 1 + + +class CustomBooleanValueFactory(DjangoModelFactory): + class Meta: + model = models.CustomValue + + value = True + + +class CustomArrayValueFactory(DjangoModelFactory): + class Meta: + model = models.CustomValue + + value = [1, 2, 3] diff --git a/django_features/custom_fields/models/field.py b/django_features/custom_fields/models/field.py index 710843f..a4336e6 100644 --- a/django_features/custom_fields/models/field.py +++ b/django_features/custom_fields/models/field.py @@ -7,6 +7,25 @@ from rest_framework import serializers +""" +CUSTOM_FIELD_BASE_MODEL_CLASS: type[TimeStampedModel] = import_string( + settings.CUSTOM_FIELD_BASE_MODEL_CLASS +) +if not issubclass(CUSTOM_FIELD_BASE_MODEL_CLASS, TimeStampedModel): + raise ValueError( + f"CUSTOM_FIELD_BASE_MODEL must inherit from TimeStampedModel, got {CUSTOM_FIELD_BASE_MODEL_CLASS}" + ) + +CUSTOM_FIELD_BASE_QUERYSET_CLASS: type[models.QuerySet] = import_string( + settings.CUSTOM_FIELD_BASE_QUERYSET_CLASS +) +if not issubclass(CUSTOM_FIELD_BASE_QUERYSET_CLASS, models.QuerySet): + raise ValueError( + f"CUSTOM_FIELD_BASE_QUERYSET must inherit from models.QuerySet, got {CUSTOM_FIELD_BASE_QUERYSET_CLASS}" + ) +""" + + class CustomFieldQuerySet(models.QuerySet): def for_model(self, model: type[models.Model]) -> "CustomFieldQuerySet": return self.select_related("content_type").filter( @@ -119,6 +138,7 @@ class Meta: verbose_name = _("Benutzerdefiniertes Feld") verbose_name_plural = _("Benutzerdefinierte Felder") ordering = ["order", "created"] + swappable = "CUSTOM_FIELD_MODEL" def __str__(self) -> str: return f"{self.label}" diff --git a/django_features/custom_fields/models/value.py b/django_features/custom_fields/models/value.py index 7704ac0..dacea82 100644 --- a/django_features/custom_fields/models/value.py +++ b/django_features/custom_fields/models/value.py @@ -1,9 +1,8 @@ +from django.conf import settings from django.db import models from django.utils.translation import gettext_lazy as _ from django_extensions.db.models import TimeStampedModel -from django_features.custom_fields.models.field import CustomField - class CustomValueQuerySet(models.QuerySet): def for_model(self, model: type[models.Model]) -> "CustomValueQuerySet": @@ -27,7 +26,7 @@ def default_for(self, model: type[models.Model]) -> "CustomValueQuerySet": class CustomValue(TimeStampedModel): field = models.ForeignKey( - CustomField, + settings.CUSTOM_FIELD_MODEL, related_name="values", verbose_name=_("Feld"), on_delete=models.CASCADE, diff --git a/django_features/custom_fields/serializers.py b/django_features/custom_fields/serializers.py index 255913f..5121304 100644 --- a/django_features/custom_fields/serializers.py +++ b/django_features/custom_fields/serializers.py @@ -5,6 +5,7 @@ from rest_framework import serializers from rest_framework.fields import empty +from django_features.custom_fields import get_custom_field_model from django_features.custom_fields.models import CustomField from django_features.custom_fields.models import CustomFieldBaseModel from django_features.custom_fields.models import CustomValue @@ -28,7 +29,7 @@ class CustomFieldSerializer(serializers.ModelSerializer): choices = serializers.SerializerMethodField() class Meta: - model = CustomField + model = get_custom_field_model() fields = [ "choice_field", "choices", @@ -99,7 +100,7 @@ def get_fields(self) -> dict[str, Any]: if self.exclude_custom_fields: return fields self._custom_fields = [] - custom_fields = list(CustomField.objects.for_model(self.model)) + custom_fields = list(get_custom_field_model().objects.for_model(self.model)) for field in custom_fields: self._custom_fields.append( CustomFieldData( diff --git a/django_features/custom_fields/viewsets.py b/django_features/custom_fields/viewsets.py index 244130c..47c16c8 100644 --- a/django_features/custom_fields/viewsets.py +++ b/django_features/custom_fields/viewsets.py @@ -1,12 +1,13 @@ from django.db.models import QuerySet from rest_framework.viewsets import ReadOnlyModelViewSet +from django_features.custom_fields import get_custom_field_model from django_features.custom_fields import models from django_features.custom_fields import serializers class CustomFieldViewSet(ReadOnlyModelViewSet): - queryset = models.CustomField.objects.all() + queryset = get_custom_field_model().objects.all() serializer_class = serializers.CustomFieldSerializer valid_content_type_filter_fields = ["app_label", "model"] diff --git a/django_features/settings/__init__.py b/django_features/settings/__init__.py index 5c2249c..7a73799 100644 --- a/django_features/settings/__init__.py +++ b/django_features/settings/__init__.py @@ -12,6 +12,11 @@ def INSTALLED_APPS(self) -> list[str]: CUSTOM_FIELD_APP = values.Value("django_features.custom_fields") + CUSTOM_FIELD_BASE_MODEL_CLASS = "django_extensions.db.models.TimeStampedModel" + CUSTOM_FIELD_BASE_QUERYSET_CLASS = "django.db.models.QuerySet" + + CUSTOM_FIELD_MODEL = "custom_fields.CustomField" + @property def CUSTOM_FIELDS_FEATURE(self) -> bool: return self.CUSTOM_FIELD_APP in self.INSTALLED_APPS diff --git a/app/tests/system_message/factories.py b/django_features/system_message/factories.py similarity index 76% rename from app/tests/system_message/factories.py rename to django_features/system_message/factories.py index e43a1a2..5169c59 100644 --- a/app/tests/system_message/factories.py +++ b/django_features/system_message/factories.py @@ -1,13 +1,13 @@ import datetime from factory import SubFactory +from factory.django import DjangoModelFactory from pytz import UTC -from app.tests.factories import BaseFactory from django_features.system_message import models -class SystemMessageTypeFactory(BaseFactory): +class SystemMessageTypeFactory(DjangoModelFactory): class Meta: model = models.SystemMessageType @@ -15,7 +15,7 @@ class Meta: icon = "information" -class SystemMessageFactory(BaseFactory): +class SystemMessageFactory(DjangoModelFactory): class Meta: model = models.SystemMessage