Django Rest Framework 如何更新 SerializerMethodField

Django Rest Framework How to update SerializerMethodField

我有一个像这样的序列化程序:

class PersonSerializer(serializers.ModelSerializer):
    gender = serializers.SerializerMethodField()
    bio = BioSerializer()

    class Meta:
        model = Person
        fields = UserSerializer.Meta.fields + ('gender', 'bio',)

    def get_gender(self, obj):
        return obj.get_gender_display()

我在执行 GET 请求时用它来显示 "Male" 和 "Female"(代替 "F" 的 "M")。

这很好用。

但是现在我正在为模型编写补丁方法并且SerializerMethodField()read_only=True。所以我没有在 serializer.validated_data() 中为性别字段传递值。如何克服这个问题?

因此,如果我理解正确的话,您想在 PATCH 请求中发送 {'gender': 'Male'}。

因此,您必须告诉您的序列化程序如何将您的表示形式(即 'Male' 转换为内部值。

如您所愿see in source,SerializerMethodField 仅涵盖从内部值到表示的转换。

您可以实施自定义 SerializerField 来执行必要的转换。天真的实现可能是这样的:

class GenderSerializerField(serializers.Field):

    VALUE_MAP = {
        'M': 'Male',
        'F': 'Female'
    }

    def to_representation(self, obj):
        return self.VALUE_MAP[obj]            

    def to_internal_value(self, data):
        return {k:v for v,k in self.VALUE_MAP.items()}[data]

class PersonSerializer(serializers.ModelSerializer):
    gender = GenderSerializerField()
    ...

请注意,此内容未经测试且缺乏任何验证,请查看 DRF docs on custom fields

除了公认的答案外,还可以有其他更简单的钩子。如果 'create' 和 'update' 在修改 gender 字段之前如您所愿地工作,那么您可以按照以下步骤将创建和更新请求的所有内容设置为默认值。

  • 不要用户SerializerMethodField。而是覆盖序列化程序表示。
class PersonSerializer(serializers.ModelSerializer):
    bio = BioSerializer()
    
    class Meta:
        model = Person
        fields = UserSerializer.Meta.fields + ('bio',)


    def to_representation(self, obj):
        ret = super().to_representation(obj)
        ret['gender'] = obj.get_gender_display()
        return ret

  • 覆盖 __init__ 方法。 .
class PersonSerializer(serializers.ModelSerializer):
    bio = BioSerializer()
    
     def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        try:
            if self.context['request'].method in ['GET']:
                self.fields['gender'] = serializers.SerializerMethodField()
        except KeyError:
            pass

    class Meta:
        model = Person
        fields = UserSerializer.Meta.fields + ('bio',)

    def get_gender(self, obj):
        return obj.get_gender_display()