66

from the documentation:

read_only Set this to True to ensure that the field is used when serializing a representation, but is not used when updating an instance during deserialization.

Defaults to False

required Normally an error will be raised if a field is not supplied during deserialization. Set to false if this field is not required to be present during deserialization.

Defaults to True.

So I have a model which has a field that's not nullable but I want it to be populated in the pre_save method, so I have set the field to required=False in serializer, but doesn't seem to work. I am still getting error when saving the record.

class FavoriteListSerializer(serializers.ModelSerializer):
    owner = serializers.IntegerField(required=False)
    class Meta:
        model = models.FavoriteList

Update: I have added serializer_class = serializers.FavoriteListSerializer to the ViewSet, now instead of getting This field is required, which I think got past the validation but then I am getting This field cannot be null. I have checked the pre_save method is not being executed, any ideas?

Hunsu
  • 3,281
  • 7
  • 29
  • 64
James Lin
  • 25,028
  • 36
  • 133
  • 233

7 Answers7

59

Yeah, I ran into this issue at some point as well. You need to also update the validation exclusions.

class FavoriteListSerializer(serializers.ModelSerializer):
    owner = serializers.IntegerField(required=False)
    class Meta:
        model = models.FavoriteList

    def get_validation_exclusions(self):
        exclusions = super(FavoriteListSerializer, self).get_validation_exclusions()
        return exclusions + ['owner']
Kevin Stone
  • 8,831
  • 41
  • 29
  • Hmmm I see, based on your answer, I tried adding validators=[] to serializer fields and still doesn't work. This kind of things are not working as advertised... – James Lin Nov 05 '13 at 18:28
  • Did you add the `get_validation_exclusions()` method? It overrides the existing validations on the model. – Kevin Stone Nov 05 '13 at 22:09
  • Yes after adding that method works. I was trying to add validators=[] to avoid overwriting get_validation_exclusions() but it didn't work – James Lin Nov 05 '13 at 22:48
  • If you read through the source, `ModelSerializer`'s implementation grabs all listed serializer fields that are listed in the serializer, but adds back any model fields that aren't read-only or another ModelSerializer. So, you have to help it out by removing the fields your view code is going to contribute. – Kevin Stone Nov 05 '13 at 23:32
  • 5
    Thanks, I still think this is a defect/imperfection as per documentation. – James Lin Nov 06 '13 at 06:02
  • 1
    Tend to agree, you should leave an issue on the project https://github.com/tomchristie/django-rest-framework/issues?state=open – Kevin Stone Nov 06 '13 at 07:39
  • 10
    I have raised an issue with the author and it's accepted. https://github.com/tomchristie/django-rest-framework/issues/1257 – James Lin Dec 05 '13 at 20:40
  • In 2020 it seems we do not need this anymore, however, it turned out that if owner is used with `unique_together` it has to be required. As a workaround, set the default=None in the serializer field constructor: https://github.com/encode/django-rest-framework/issues/4456 – math Jan 06 '20 at 15:03
  • Is everything in django just wanky and broken, every time I do something intuitive django is there to show me NOPE, you need to do some convoluted googling and changing before you do what you are obviously trying to d. – E.Serra Aug 06 '20 at 16:32
  • You can find better solution here - https://stackoverflow.com/a/29621808/7681229 – Zhong Ri Nov 09 '20 at 09:40
40

Late Entry to this thread. This issue was fixed in django-rest-framework 2.3.13. Here is the link of the PR.

You use it like this in your case:

    class Meta:
        model = models.FavoriteList
        optional_fields = ['owner', ]
Olivier Pons
  • 15,363
  • 26
  • 117
  • 213
Pankaj Singhal
  • 15,283
  • 9
  • 47
  • 86
  • I've edited this to add a sample just in case. You should be "up" 40x to be on top because the answer with `get_validation_exclusions()` is not valid anymore (it was never called and PyCharm said there's no other declaration but mine to be found, so it's not the right solution). – Olivier Pons Oct 15 '19 at 14:51
  • 1
    I guess you meant 10x. 40x would be 160 which is 4 times 40. I can't do anything to reach there . Thanks for adding the sample, BTW. – Pankaj Singhal Oct 15 '19 at 18:42
  • 3
    This does not seem to exist anymore in the current version. – Jurrian Mar 22 '23 at 22:37
36

In case somebody lands here with a similar issue, pay attention to the following attributes along with required:

allow_blank:

If set to True then the empty string should be considered a valid value.

allow_null:

Normally an error will be raised if None is passed to a serializer field.

required:

Normally an error will be raised if a field is not supplied during deserialization.

I was straggling to figure out why I was getting a validation error with required=False where I had missed the allow_null attribute.

Wtower
  • 18,848
  • 11
  • 103
  • 80
22

In 2020, for DRF 3.12.x, the approach that I prefer the approach that relies on Serializer's extra_kwargs.

So assuming your

class FavoriteListSerializer(serializers.ModelSerializer):
    owner = serializers.IntegerField(required=False)
    class Meta:
        model = models.FavoriteList
        fields = ["owner"]  # and whatever other fields you want to expose
        extra_kwargs = {"owner": {"required": False, "allow_null": True}}
4

If you have unique_together constraint on one of the fields you are trying to set required=False you need to set validators=[] in serializers Meta like

class FavoriteListSerializer(serializers.ModelSerializer):
    owner = serializers.IntegerField(required=False)
    class Meta:
        model = models.FavoriteList
        validators = []

Here is the original answer

Vaghinak
  • 535
  • 6
  • 12
1

You can also do this:

class ASerializer(serializers.HyperlinkedModelSerializer): 
    owner = serializers.HiddenField(default=serializers.CurrentUserDefault())

    ...

As referred here: https://www.django-rest-framework.org/api-guide/validators/#advanced-field-defaults There you can also find the case when you also wanna let the view show owner

Michele
  • 103
  • 1
  • 7
0

I would set model field to allow null value (and possible also default to None)

class FavoriteList(models.Model):
    owner = models.PositiveIntegerField(null=True, default=None)

Then it's possible to just leave owner field to Meta section. These fields, without any extra settings, will automatically get all attributes from model field and be non-required.

class FavoriteListSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.FavoriteList
        fields = ('owner',)
TCFDS
  • 584
  • 4
  • 16