为什么django-rest-frameworks request.data有时是不可变的?

时间:2018-09-17 12:05:50

标签: python django django-rest-framework

在安静的CreateAPIView中,我突变了request.data字典。

有时,我会收到一个未被测试发现的错误:

This QueryDict instance is immutable

例如这个:

class CreateView(CreateAPIView):
    serializer_class = ...
    queryset = ...

    def post(self, request, *args, **kwargs):
        request.data['user'] = request.user.pk
        return self.create(request, *args, **kwargs)

request.data在我的测试中似乎是正常的dict。为什么有时有时QueryDict?应该如何处理?一般而言,request.data不应被突变吗?当您需要自己填充某些字段时,应该如何使用ModelSerializer类?

4 个答案:

答案 0 :(得分:5)

  

为什么这种偶然行为?

当我们查看SC of Request(如@Kenny Ackerman提到的)时,如果您传递的是 表单媒体,它将返回 QueryDict 对象在视图类中输入 'application/x-www-form-urlencoded''multipart/form-data')数据。
该检查在 {{ 1}} 类。

如果要将Request数据传递到视图,则 application/json 将是 request.data 对象。

  

如何重现行为?

可以通过向视图中发送不同的dict数据来进行复制。 (在POSTMAN工具中,使用ContentTypeform-data来获取行为)


  

如何在序列化程序中获取 当前登录用户

方法1 通过覆盖 raw JSON 将额外的参数传递给 .save() (如@Linovia所述)方法

perform_create()

方法2 使用is_form_media_type()类,如下所示

class CreateView(CreateAPIView):
    serializer_class = ...
    queryset = ...

    def post(self, request, *args, **kwargs):
        request.data['user'] = request.user.pk
        return self.create(request, *args, **kwargs)

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

答案 1 :(得分:1)

基于source code解析器,当流为空(request.data调用_load_data_and_files方法和_load_data_and_files调用_parse方法)时,对数据返回一个querydict。

,我认为您可以使用HiddenField填充字段,也可以覆盖createupdate方法。例如

class TestSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    class Meta:
        model = Test
        fields = ('id', 'text', 'user')

    def create(self, validated_data):

        validated_data['populate_field'] = 'value'
        return super().create(validated_data)

答案 2 :(得分:1)

当您必须修改从请求接收到的QueryDict对象时,它是一个不可变的对象,如果要添加属性,请改用以下代码:

myNewRequest = request.GET.copy()
myNewRequest.data['some_attr'] = float(something)

答案 3 :(得分:0)

请注意,这实际上取决于rest_framework的DEFAULT_PARSER_CLASSES中指定的所选解析器和请求的内容类型:

JSONParser的实现如下:

return json.load(decoded_stream, parse_constant=parse_constant)

FormParser如下:

return QueryDict(stream.read(), encoding=encoding)