Django Rest Framework“此字段为必填"仅当发布JSON时,而不是发布表单内容时 [英] Django Rest Framework "This field is required" only when POSTing JSON, not when POSTing form content
问题描述
我得到一个奇怪的结果,将 POST
JSON复制到DRF端点会返回:
I'm getting a strange result whereby POST
ing JSON to a DRF endpoint returns:
{"photos":["This field is required."],"tags":["This field is required."]}'
而 POST
表单数据DRF并不介意字段为空.
Whereas when POST
ing 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
- 对于某些输入(包括复选框和允许多项选择的其他输入),没有空"或空"数据的概念.
- 没有输入类型支持单个字段的多个值,复选框是一个例外.
这两种方法结合在一起,使得在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.
- 如果未传入字段,则假定为
None
或该字段的默认值.这是因为没有值的输入不会在表单数据中传递,因此缺少其键. - 如果将单个值传递给多值字段,则将其视为一个选定值.这是因为从多个表单中选择的一个复选框与表单数据中的一个复选框完全没有区别.两者都作为单个键传递.
- 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. - 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屋!