Django Rest Framework只有在POST JSON时才需要“此字段”,而不是在POST表单内容时

时间:2015-06-12 12:12:30

标签: django-rest-framework

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

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

POST表单数据时,DRF并不介意字段为空。

我的模特是:

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

1 个答案:

答案 0 :(得分:5)

这里的问题起初并不明显,但它与表单数据的缺点以及如何处理部分数据有关。

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

  1. 某些输入没有“空”或“空”数据的概念,包括允许多项选择的复选框和其他输入。
  2. 没有输入类型支持单个字段的多个值,复选框是一个例外。
  3. 这两者结合在一起使得难以在Django REST框架中处理接受表单数据,因此它必须处理与大多数解析器不同的一些事情。

    1. 如果未传入字段,则假定为None或字段的默认值。这是因为没有值的输入不会在表单数据中传递,因此缺少其键。
    2. 如果为多值字段传入单个值,则会将其视为一个选定值。这是因为在表单数据中从多个复选框和单个复选框中选择的单个复选框之间没有区别。它们都作为单个密钥传入。
    3. 但同样不适用于JSON。由于您没有为photostags密钥传递空列表,因此DRF不知道为默认值提供什么,并且不会将其传递给序列化程序。因此,序列化程序发现没有传入任何内容并触发验证错误,因为未提供必填字段。

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