简体   繁体   English

Python - 无法修改 Django Rest Framework 中的 serializer.data 字典

[英]Python - Unable to modify the serializer.data dictionary in Django Rest Framework

I have tried to add a key serializer.data['test'] = 'asdf' , this does not appear to do anything.我试图添加一个密钥serializer.data['test'] = 'asdf' ,这似乎没有做任何事情。

I want to transform the representation of a key's value.我想转换键值的表示。 To do this, I'm trying to use the value to calculate a new value and replace the old one in the dictionary.为此,我尝试使用该值来计算新值并替换字典中的旧值。

This is what I want to accomplish, but I don't know why the value is not being replaced.这是我想要完成的,但我不知道为什么值没有被替换。 There are no errors thrown, and the resulting dictionary has no evidence that I've tried to replace anything:没有抛出任何错误,生成的字典没有证据表明我试图替换任何内容:

class PlaceDetail(APIView):
    def get(self, request, pk, format=None):
        place = Place.objects.select_related().get(pk=pk)
        serializer = PlaceSerializer(place)
        #serializer.data['tags'] = pivot_tags(serializer.data['tags'])
        serializer.data['test'] = 'asdf'
        print(serializer.data['test'])
        return Response(serializer.data)

Terminal: KeyError: 'test'终端: KeyError: 'test'

I have observed by printing that serializer.data is a dictionary.我通过打印serializer.data是一本字典观察到。

I have also tested that the syntax I'm trying to use should work:我还测试过我尝试使用的语法应该有效:

>>> test = {'a': 'Alpha'}
>>> test
{'a': 'Alpha'}
>>> test['a']
'Alpha'
>>> test['a'] = 'asdf'
>>> test
{'a': 'asdf'}

How can I properly modify the serializer.data dictionary?如何正确修改serializer.data字典?

The Serializer.data property returns an OrderedDict which is constructed using serializer._data . Serializer.data属性返回一个使用serializer._data构造的OrderedDict The return value is not serializer._data itself.返回值不是serializer._data本身。

Thus changing the return value of serializer.data does not change serializer._data member.因此改变serializer.data的返回值不会改变serializer._data成员。 As a consequence, the following calls to serializer.data are not changed.因此,不会更改以下对serializer.data调用。

# In class Serializer(BaseSerializer)
@property
def data(self):
    ret = super(Serializer, self).data
    return ReturnDict(ret, serializer=self)

# In class ReturnDict(OrderedDict)
def __init__(self, *args, **kwargs):
    self.serializer = kwargs.pop('serializer')
    super(ReturnDict, self).__init__(*args, **kwargs)

You can keep a copy of the return value of serializer.data , which is an ordered dictionary, and manipulate it as you wish.您可以保留一个serializer.data返回值的副本,它是一个有序的字典,并根据需要对其进行操作。

Example:例子:

# keep the return value of serializer.data
serialized_data = serializer.data
# Manipulate it as you wish
serialized_data['test'] = 'I am cute'
# Return the manipulated dict
return Response(serialized_data)

Why:为什么:

If you look at the source code of Django Restframework, you will see that in Serializer class,如果你查看 Django Restframework 的源代码,你会在Serializer类中看到,

  • Serializer._data is just a normal dictionary. Serializer._data只是一个普通的字典。
  • Serializer.data is a method decorated to act like a property. Serializer.data是一种装饰成属性的方法。 It returns a ReturnDict object, which is a customized class derived from OrderedDict .它返回一个ReturnDict对象,该对象是从OrderedDict派生的自定义类。 The returned ReturnDict object is initialized using key/value pairs in Serializer._data .返回的ReturnDict对象使用Serializer._data键/值对进行初始化。

If Serializer.data returns Serializer._data directly, then your original method will work as you expected.如果Serializer.data直接返回Serializer._data ,那么您的原始方法将按您的预期工作。 But it won't work since it's returning another dictionary-like object constructed using Serializer._data .但它不会工作,因为它返回另一个使用Serializer._data构造的类似字典的对象。

Just keep in mind that the return value of Serializer.data is not Serializer._data , but an ordered dictionary-like object.请记住, Serializer.data的返回值不是Serializer._data ,而是一个有序的类似字典的对象。 Manipulating the return value does not change Serializer._data .操作返回值不会改变Serializer._data

I believe the reason why serializer.data does not return serializer._data directly is to avoid accidental change of the data and to return a pretty representation of serializer._data .我相信serializer.data不直接返回serializer._data的原因是为了避免数据的意外更改并返回serializer._data的漂亮表示。

You'll want to use SerializerMethodField instead of explicitly overwrite the representations.您需要使用SerializerMethodField而不是显式覆盖表示。

Building further on @yuwang's answer, I used SerializerMethodField to modify value of a particular field in the serializer.在@yuwang 的回答的基础上进一步构建,我使用SerializerMethodField来修改SerializerMethodField程序中特定字段的值。 Here's an example:下面是一个例子:

The field that I wanted to modify, let us call it is_modifyable .我想修改的字段,我们称之为is_modifyable This field is present on the Django Model as models.BooleanField and hence it was not present in the list of fields on serializer definition and simply mentioned in the class Meta: definition under within the serializer definition.这个字段在 Django 模型中作为models.BooleanField ,因此它没有出现在序列化器定义的字段列表中,只是在序列化器定义下的class Meta: definition 中提到。

So here's how my code looked before:所以这是我的代码之前的样子:

# in models.py
# Model definition
class SomeModel(models.Model):
    is_modifyable = models.BooleanField(default=True)

# in serializers.py
# Serializer definition
class SomeModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = SomeModel
        fields = ('is_modifyable',)

As a result of the above, the value for the field is_modifyable was always fetched on the basis of what the value was in the record of SomeModel object.作为上述结果,字段is_modifyable的值总是根据SomeModel对象的记录中的值来SomeModel However, for some testing purpose, I wanted the value of this field to be returned as False during the development phase, hence I modified the code to be as follows:但是,出于某些测试目的,我希望在开发阶段将此字段的值返回为 False,因此我将代码修改为如下:

# in models.py
# Model definition (Left unchanged)
class SomeModel(models.Model):
    is_modifyable = models.BooleanField(default=True)

# in serializers.py
# Serializer definition (This was updated)
class SomeModelSerializer(serializers.ModelSerializer):
    # This line was added new
    is_modifyable = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = SomeModel
        fields = ('is_modifyable',)

    # get_is_modifyable function was added new
    def get_is_modifyable(self, obj) -> bool:
        """
        Dummy method to always return False for test purpose
        Returns: False
        """
        return False

Once the above code was in, the API call always returned the value of serializer field is_modifyable as False.一旦上面的代码进入,API 调用总是将序列化器字段is_modifyable的值返回为 False。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM