django-rest-framework icon indicating copy to clipboard operation
django-rest-framework copied to clipboard

Fix raising on nullable fields part of `UniqueConstraint`

Open browniebroke opened this issue 1 year ago • 2 comments

Description

Fix #9378

  • [x] Add a few failing tests
  • [x] Fix cause of the problem

browniebroke avatar Sep 11 '24 21:09 browniebroke

any progress here?

Not really, I've dropped the ball a bit on this one. Will try to make some progress...

browniebroke avatar Oct 14 '24 17:10 browniebroke

Oh well, that's all passing now... Hopefully that covers the main use case reported in https://github.com/encode/django-rest-framework/issues/9378

There is also the other semi-related bug https://github.com/encode/django-rest-framework/issues/9358 which is NOT in scope of this PR, I believe it will be fixed by https://github.com/encode/django-rest-framework/pull/9360

browniebroke avatar Oct 14 '24 18:10 browniebroke

Is a new version expected with this fix and others related like https://github.com/encode/django-rest-framework/pull/9360 ? The support for UniqueConstraint is not complete and may cause issues…

SorianoMarmol avatar Oct 23 '24 14:10 SorianoMarmol

thanks!

auvipy avatar Dec 14 '24 09:12 auvipy

I'm not entirely sure under which circumstances, but this change turns a SerializerMethodField() whose name appears in the uniqueness constraint of the underlying model into a HiddenField(default=None).

I'll keep investigating.

mdellweg avatar Apr 04 '25 14:04 mdellweg

Here is a (minimal???) reproducer:

def test_tba():
    class TestModel(models.Model):
        field_1 = models.IntegerField(null=True)
        field_2 = models.IntegerField(null=True)

        class Meta:
            unique_together = (("field_1", "field_2"),)

    class TestSerializer(serializers.ModelSerializer):
        field_1 = serializers.SerializerMethodField()

        def get_field_1(self) -> str:
            return "TEST"

        class Meta:
            model = TestModel
            fields = ["field_1", "field_2"]

    fields = TestSerializer().fields
    assert isinstance(fields["field_1"], serializers.SerializerMethodField)
    assert isinstance(fields["field_1"], serializers.SerializerMethodField)
E   AssertionError: assert False
E    +  where False = isinstance(HiddenField(default=None), <class 'rest_framework.fields.SerializerMethodField'>)
E    +    where <class 'rest_framework.fields.SerializerMethodField'> = serializers.SerializerMethodField

mdellweg avatar Apr 07 '25 14:04 mdellweg

I'm not entirely sure under which circumstances, but this change turns a SerializerMethodField() whose name appears in the uniqueness constraint of the underlying model into a HiddenField(default=None).

I'll keep investigating.

Seeing the same thing in my codebase when upgrading to 3.16!

stianjensen avatar Jun 05 '25 15:06 stianjensen