Django Rest Framework“此字段为必填"仅当发布JSON时,而不是发布表单内容时 [英] Django Rest Framework "This field is required" only when POSTing JSON, not when POSTing form content

查看:45
本文介绍了Django Rest Framework“此字段为必填"仅当发布JSON时,而不是发布表单内容时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我得到一个奇怪的结果,将 POST JSON复制到DRF端点会返回:

I'm getting a strange result whereby POSTing JSON to a DRF endpoint returns:

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

POST 表单数据DRF并不介意字段为空.

Whereas when POSTing form data DRF doesn't mind that the fields are empty.

我的模特是:

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")

我的序列化器是:

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')

我的 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)

结果:

# 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":[]}'

推荐答案

乍一看这里的问题并不明显,但这与表单数据的缺点以及如何处理部分数据有关.

The issue here isn't obvious at first, but it has to do with a shortcoming in form-data and how partial data is handled.

表单数据具有Django REST框架必须处理的两种特殊情况

Form data has two special cases that Django REST framework has to handle

  1. 对于某些输入(包括复选框和允许多项选择的其他输入),没有空"或空"数据的概念.
  2. 没有输入类型支持单个字段的多个值,复选框是一个例外.

这两种方法结合在一起,使得在Django REST框架中难以处理接受表单数据,因此它必须处理与大多数解析器不同的一些事情.

Both of these combine together to make it difficult to handle accepting form data within Django REST framework, so it has to handle a few things differently from most parsers.

  1. 如果未传入字段,则假定为 None 或该字段的默认值.这是因为没有值的输入不会在表单数据中传递,因此缺少其键.
  2. 如果将单个值传递给多值字段,则将其视为一个选定值.这是因为从多个表单中选择的一个复选框与表单数据中的一个复选框完全没有区别.两者都作为单个键传递.
  1. If a field is not passed in, it is assumed to be None or the default value for the field. This is because inputs with no values are not passed along in the form data, so their key is missing.
  2. If a single value is passed in for a multiple-value field, it will be treated like the one selected value. This is because there is no difference between a single checkbox selected out of many and a single checkbox at all in form data. Both of them are passed in as a single key.

但是同样的不适用于JSON.由于您没有传递 photos tags 键的空列表,因此DRF不知道为默认值提供什么,因此不会将其传递给序列化器.因此,序列化程序发现没有传入任何内容,并由于未提供必填字段而触发了验证错误.

But the same doesn't apply to JSON. Because you are not passing an empty list in for the photos and tags keys, DRF does not know what to give it for a default value and does not pass it along to the serializer. Because of this, the serializer sees that there is nothing passed in and triggers the validation error because the required field was not provided.

因此,解决方案是在使用JSON时始终提供所有密钥(不包括 PATCH 请求,这可能是部分请求),即使它们不包含任何数据.

So the solution is to always provide all keys when using JSON (not including PATCH requests, which can be partial), even if they contain no data.

这篇关于Django Rest Framework“此字段为必填"仅当发布JSON时,而不是发布表单内容时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆