HTTP POST请求有效内容为空时不完整的验证消息

时间:2017-08-16 04:12:53

标签: django django-rest-framework

这是我的模特:

class Profile(models.Model):
    user = models.OneToOneField(User)
    phone = models.CharField(max_length=20, blank=True, null=True)
    designation = models.CharField(max_length=50, blank=True, null=True)
    roles = models.ManyToManyField(Role, related_name="profiles")

这是序列化器:

class UserSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(
        required=True, validators=[UniqueValidator(queryset=User.objects.all())])
    full_name = serializers.CharField(max_length=60, write_only=True)
    phone = serializers.CharField(
        max_length=20, allow_blank=True, required=False, write_only=True)
    designation = serializers.CharField(
        max_length=50, allow_blank=True, required=False, write_only=True)
    roles = serializers.MultipleChoiceField(
        choices=models.Role.objects.values_list('id', flat=True), write_only=True)

    class Meta:
        model = User
        fields = ('id', 'email', 'full_name', 'phone', 'designation', 'roles')

问题

所有请求均以Content-Type: application/json

发送
  1. 当我使用空有效负载发布请求时,DRF会引发400(必填字段不完整)

    {
      "full_name": [
        "required"
      ],
      "email": [
        "required"
      ],
    }
    
  2. 当POST请求正文为{}时,DRF会引发400,包含所有必填字段

    {
      "full_name": [
        "required"
      ],
      "email": [
        "required"
      ],
      "roles": [
        "required"
      ]
    }
    
  3. 问题

    如果请求正文为空,我如何确保DRF提出ParseError

    已经尝试

    1. 在UserSerializer中向角色添加allow_blankrequired无效。
    2. 使用APITestCase测试时没有不一致。我可以通过ARC重现错误。
    3. 解决方法

      添加了一个自定义异常处理程序,用于检查:

      request = context['request']
      if request.content_type == 'application/json' and type(request.data) != dict:
          return response.Response(
              {'detail': 'Invalid body'}, status=status.HTTP_400_BAD_REQUEST)
      

      当请求正文为空时,request.data为django.http.QueryDict。这是我正在检查的。但是,我更倾向于在其原点引发此错误,而不是检查它产生的副作用。

1 个答案:

答案 0 :(得分:1)

使用普通DRF功能似乎无法做到这一点。如果响应正文为空,request._parse()方法不会调用任何解析器,它只会返回默认值{}

这意味着您无法换出解析器并在某些端点上获得所需的行为。

# request.py @ 301
if stream is None or media_type is None:
    if media_type and not is_form_media_type(media_type):
        empty_data = QueryDict('', encoding=self._request._encoding)
    else:
        empty_data = {}
    empty_files = MultiValueDict()
    return (empty_data, empty_files)

parser = self.negotiator.select_parser(self, self.parser

<强>买者

你想要的行为有点不寻常;我认为DRF正在正确处理事情,但我可以理解为什么你想要一个不同的行为。也许这是DRF gihub中功能请求的内容? &#34;解析时添加allow_empty_body标志(默认为True)。

注意:在请求中,空请求正文合法。例如,您可以使用它们来触发对象(例如post /api/accounts/592/disable/

)的操作

如果你想要完成这个,有一些选择,但它们都很尴尬,可能会以某种方式破坏。

#1 django中间件

您可以为django编写一个中间件类来检查post和空体的传入请求,并手动返回错误。

#2 monkeypatch请求类

您可以在应用启动时使用您的DRF请求类覆盖_parse()方法。

<强>其他

可能在序列化程序中做一些疯狂的事情,或者手动检查post(self, request, **kwargs)方法是否有空请求,但它们都有点hacky。