BUG in 3.16.0: UniqueConstraint removes field from Serializer

120 views
Skip to first unread message

Martin Reidemeister

unread,
Apr 1, 2025, 2:52:22 AMApr 1
to Django REST framework
I experience a bug with DRF 3.16.0.

I created a minimal example:

# model.py
from django.db.models import CharField, IntegerField, Model, UniqueConstraint

class MyModel(Model):
    class Meta:
        abstract = True

    foo = IntegerField(null=True, blank=True)
    bar = CharField(max_length=100)


class ModelWithoutUniqueConstraint(MyModel):
    pass

class ModelWithUniqueConstraint(MyModel):
    class Meta:
        constraints = [UniqueConstraint(fields=("bar", "foo"), name="unique_bar_and_foo", nulls_distinct=False)]

# view_rest.py
from rest_framework.fields import SerializerMethodField
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ReadOnlyModelViewSet

from myapp.models import ModelWithoutUniqueConstraint, ModelWithUniqueConstraint


class BaseModelSerializer(ModelSerializer):
    class Meta:
        fields = ("id", "foo", "bar")

    foo = SerializerMethodField()

    @staticmethod
    def get_foo(obj: ModelWithUniqueConstraint) -> int | None:
        return obj.foo

class ModelWithUniqueConstraintSerializer(BaseModelSerializer):
    class Meta(BaseModelSerializer.Meta):
        model = ModelWithUniqueConstraint

class ModelWithoutUniqueConstraintSerializer(BaseModelSerializer):
    class Meta(BaseModelSerializer.Meta):
        model = ModelWithoutUniqueConstraint

class ModelWithUniqueConstraintViewSet(ReadOnlyModelViewSet):
    queryset = ModelWithUniqueConstraint.objects.all()
    serializer_class = ModelWithUniqueConstraintSerializer

class ModelWithoutUniqueConstraintViewSet(ReadOnlyModelViewSet):
    queryset = ModelWithoutUniqueConstraint.objects.all()
    serializer_class = ModelWithoutUniqueConstraintSerializer

In the result of ModelWithUniqueConstraintViewSet the field "foo" is lost whith DRF 3.16. while it works with 3.15.2

My current dependencies are:
asgiref==3.8.1
attrs==25.3.0
django==5.1.7
djangorestframework==3.16.0
drf-spectacular==0.28.0
inflection==0.5.1
jsonschema==4.23.0
jsonschema-specifications==2024.10.1
pyyaml==6.0.2
referencing==0.36.2
rpds-py==0.24.0
sqlparse==0.5.3
typing-extensions==4.13.0 ; python_full_version < '3.13'
tzdata==2025.2 ; sys_platform == 'win32'
uritemplate==4.1.1

Onjomba Felix

unread,
Apr 1, 2025, 3:34:16 AMApr 1
to django-res...@googlegroups.com

This looks like a bug in Django REST Framework (DRF) 3.16.0, where the UniqueConstraint might be affecting field serialization. In DRF 3.15.2, the foo field was included, but in DRF 3.16.0, it disappears.

Possible Workarounds

1. Explicitly Declare foo in Meta.fields

Since foo is being removed when using UniqueConstraint, you can explicitly list it in Meta.fields:

class BaseModelSerializer(ModelSerializer): foo = SerializerMethodField() class Meta: model = None # Override in subclasses fields = ("id", "foo", "bar") # Explicitly include `foo` @staticmethod def get_foo(obj) -> int | None: return obj.foo
2. Use extra_kwargs to Force Inclusion

Another workaround is using extra_kwargs in the serializer:

class BaseModelSerializer(ModelSerializer): class Meta: model = None # Override in subclasses
fields = ("id", "foo", "bar"
) extra_kwargs = {"foo": {"read_only": True}}

3. Manually Add foo in to_representation

If the issue persists, override to_representation to ensure foo is serialized:

class BaseModelSerializer(ModelSerializer): class Meta: fields = ("id", "bar") # Exclude `foo` here to manually add def to_representation(self, instance): data = super().to_representation(instance) data["foo"] = instance.foo # Ensure `foo` is added back return data

--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-fram...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/django-rest-framework/7922c7ed-15b2-4544-b6a7-c959df9af55an%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages