Django Rest Framework 如何更新 SerializerMethodField

Posted

技术标签:

【中文标题】Django Rest Framework 如何更新 SerializerMethodField【英文标题】:Django Rest Framework How to update SerializerMethodField 【发布时间】:2016-09-25 08:12:16 【问题描述】:

我有一个这样的序列化器:

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() 中为性别字段传递值。如何克服这个问题?

【问题讨论】:

【参考方案1】:

所以,如果我理解正确,您想在 PATCH 请求中发送 'gender': '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。

【讨论】:

我按照你说的做了,但它不起作用。在这种情况下,序列化程序也没有检测到任何名为“gender”的键。顺便说一句,serializers.Serializer 在类参数中,因为它说 serailizers 没有像 SerializerField 这样的字段 对不起,基类是错误的(我假设这就是您对“类参数”的意思)。它应该是 serializers.Field 而不是 serializers.SerializerField @kishan 很高兴我能帮上忙!如果我的回答为您解决了问题,请随时单击复选标记接受它。谢谢! 为什么要在使用前创建字典的副本? return VALUE_MAP[data] 不也可以吗? @JensTimmerman 我的意图是反转字典,但代码错误。它现在是固定的(k,v 而不是 v,k)。很好,谢谢!【参考方案2】:

除了接受的答案之外,还可以有其他更简单的钩子。如果在修改 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()   

【讨论】:

以上是关于Django Rest Framework 如何更新 SerializerMethodField的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Postman 表单数据在 Django REST Framework 中发布嵌套数组?

django-rest-framework:如何序列化已经包含 JSON 的字段?

如何仅使用 django 作为后端并使用 django-rest-framework 发布

如何在 django-rest-framework 中为 API 使用 TokenAuthentication

django-rest-framework指南:Requests and Responses

django-rest-framework - 在可浏览的 API 中自动生成表单?