Django Rest Framework "This field is required" only when POSTing JSON, not when filling out a POSTing form

I am getting a weird result where POST

including JSON in the DRF endpoint returns:

{"photos":["This field is required."],"tags":["This field is required."]}'

      

If the POST

ing data of the DRF form does not take into account that the fields are empty.

My model:

class Story(CommonInfo):
    user = models.ForeignKey(User)
    text = models.TextField(max_length=5000,blank=True)
    feature = models.ForeignKey("Feature", blank=True, null=True)
    tags = models.ManyToManyField("Tag")

      

My serializer:

class StorySerializer(serializers.HyperlinkedModelSerializer):
    user = serializers.CharField(read_only=True) 

    def get_fields(self, *args, **kwargs):
        user = self.context['request'].user
        fields = super(StorySerializer, self).get_fields(*args, **kwargs)
        fields['feature'].queryset = fields['feature'].queryset.filter(user=user)
        fields['photos'].child_relation.queryset = fields['photos'].child_relation.queryset.filter(user=user)
        return fields

    class Meta:
        model = Story
        fields = ('url', 'user', 'text', 'photos', 'feature', 'tags')

      

And mine api.py

:

class StoryViewSet(viewsets.ModelViewSet):
    serializer_class = StorySerializer

    def get_queryset(self):
        return self.request.user.story_set.all()

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

      

Results:

# JSON request doesn't work
IN: requests.post("http://localhost:8001/api/stories/",
               auth=("user", "password",),
               data=json.dumps({'text': 'NEW ONE!'}),
               headers={'Content-type': 'application/json'}
              ).content
OUT: '{"photos":["This field is required."],"tags":["This field is required."]}'

# Form data request does work
IN: requests.post("http://localhost:8001/api/stories/",
               auth=("user", "password",),
               data={'text': 'NEW ONE!'},
              ).content
OUT: '{"url":"http://localhost:8001/api/stories/277/","user":"user","text":"NEW ONE!","photos":[],"feature":null,"tags":[]}'

      

+3


source to share


1 answer


The problem here isn't obvious at first, but it has to do with the lack of form data and how the partial data is handled.

Form data has two special cases that the Django REST framework must handle

  • For some inputs, there is no concept of "null" or "blank" data, including checkboxes and other inputs that allow multiple choices.
  • There is no input type that supports multiple values ​​for a single field, with exceptions being the exception.

Both of these unions combine to make it difficult for Django REST to handle the received form data, so it has to handle a few different things than most parsers.



  • If the field is not passed, it is considered None

    either the default value for the field. This is because data inputs without values ​​are not passed in the form data, so their key is missing.
  • If a single value is passed for a field with multiple values, it will be treated as one selected value. This is because there is no difference between one checkbox selected from many and one checkbox at all in the form data. Both are transmitted as one key.

But the same is not true for JSON. Since you are not passing an empty list for keys photos

and tags

, DRF does not know what to give it a default value and does not pass it along with the serializer. Because of this, the serializer sees that nothing passed and triggers a validation error because the required field was not provided.

So the solution is to always provide all keys when using JSON (not including requests PATCH

, which might be partial), even if they do not contain data.

+4


source







All Articles