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

时间:2016-02-16 02:36:58

标签: python dictionary django-rest-framework

我尝试添加密钥serializer.data['test'] = 'asdf',但这似乎没有做任何事情。

我想转换键值的表示。为此,我尝试使用该值来计算新值并替换字典中的旧值。

这是我想要完成的,但我不知道为什么价值没有被取代。没有抛出错误,结果字典没有证据表明我试图替换任何东西:

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)

终端:KeyError: 'test'

我通过打印观察到serializer.data是一本字典。

我还测试了我尝试使用的语法应该有效:

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

如何正确修改serializer.data字典?

3 个答案:

答案 0 :(得分:11)

Serializer.data属性返回使用OrderedDict构建的serializer._data。返回值本身不是serializer._data

因此,更改serializer.data的返回值不会更改serializer._data成员。因此,以下对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)

您可以保留serializer.data的返回值的副本,这是一个有序的字典,并根据需要进行操作。

实施例:

# 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)

为什么:

如果你看一下Django Restframework的源代码,你会在Serializer类中看到,

  • Serializer._data只是一个普通的字典。
  • Serializer.data是一种装饰成属性的方法。它返回一个ReturnDict对象,该对象是从OrderedDict派生的自定义类。使用ReturnDict中的键/值对初始化返回的Serializer._data对象。

如果Serializer.data直接返回Serializer._data,那么您的原始方法将按预期工作。但它不会起作用,因为它返回了另一个使用Serializer._data构造的类字典对象。

请记住,Serializer.data的返回值不是Serializer._data,而是一个有序的字典对象。操纵返回值不会改变Serializer._data

我认为serializer.data不直接返回serializer._data的原因是为了避免意外更改数据并返回serializer._data的漂亮表示。

答案 1 :(得分:0)

您需要使用SerializerMethodField,而不是明确覆盖表示。

答案 2 :(得分:0)

根据@yuwang的答案,我使用SerializerMethodField来修改序列化程序中特定字段的值。这是一个示例:

我要修改的字段,我们称之为is_modifyable。该字段在Django模型中以models.BooleanField的形式出现,因此在序列化程序定义的字段列表中不存在,而在序列化程序定义下的class Meta:定义中简单提及。

所以这是我的代码之前的样子:

# 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',)

作为上述结果,总是根据is_modifyable对象的记录中的值来获取字段SomeModel的值。但是,出于某种测试目的,我希望在开发阶段将此字段的值返回为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

一旦输入了上述代码,API调用始终将序列化器字段is_modifyable的值返回为False。