如何使Serializer中的字段既可读又可写

How to make a field in Serializer both readable and writeable

我正在为我的模型编写一个序列化程序,它将使用 GET、POST 和 PATCH 端点进行访问。我的模型中有一个 属性,我将其用作字段的来源。但是,在序列化程序字段中使用 source= 使其成为只读状态。

如果我从

中删除 source="get_field1"

field1 = serializers.NullBooleanField(source="get_field1")

然后我就可以更新数据了。

但我必须使用源来获取字段的正确值。

class MyModel(models.Model):
    field1 = NullBooleanField(default=None)

    @property
    get_field1(self):
       data = True
       # ...some logic
       return data

现在我有一个正在使用的序列化器

    class MyModelSerializer(serializers.ModelSerializer):
        field1 = serializers.NullBooleanField(source="get_field1")
        class Meta:
             model = MyModel
             fields = ('field1')

现在在我的 API 端点,我这样做

    serializer = MyModelSerializer(my_model, data=request.data, partial=True)
    if serializer.is_valid():
        serializer.save() # <- throws error "can't set attribute"

此外,我想提一下,序列化程序中的字段是由 属性 名称而不是字段名称引用的。

示例:如果我这样做

>> serializer.validated_data

>> 'OrderedDict(['get_field1'], True) # <- shouldn't this by field1 and not get_field1

这可以通过覆盖序列化程序的 __init__() 方法来完成。除此之外,我们必须将一些 context 数据传递给序列化程序以区分 GETPOSTPATCH 请求。

class MyModelSerializer(serializers.ModelSerializer):
    <b>field1 = serializers.NullBooleanField()  # remove "source" argument from here

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.context['request'].method == 'GET':
            self.fields['field1'] =serializers.NullBooleanField(source= "get_field1")</b>

    class Meta:
        model = MyModel
        fields = ('field1',)

并且在序列化数据时,不要忘记将请求作为上下文传递,如

serializer = MyModelSerializer(my_model, data=request.data, partial=True, <b>context={"request": request}</b>)

@JPG 的回答很好,但我觉得这是一种 hacky 方式。

我会覆盖 Serializer 的 to_representation 方法来实现您的目的。

您可以执行以下操作

class MyModelSerializer(serializers.ModelSerializer):
        field1 = serializers.NullBooleanField() # get rid of source

        def to_representation(self, instance):
             data = super(MyModel, self).to_representation(instance)
             data.update({
                  'field1': instance.get_field1
             })
             return data       

        class Meta:
             model = MyModel
             fields = ('field1')

这样您就隐式提供了源并且您的字段变得可写。因此,每次 GET、POST 或 PATCH 时,您都会获得正确的值。