【问题标题】:Django Rest Framework How to update SerializerMethodFieldDjango Rest Framework 如何更新 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() 中为性别字段传递值。如何克服这个问题?

【问题讨论】:

    标签: python django django-rest-framework django-serializer


    【解决方案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()   
    
    

    【讨论】:

      猜你喜欢
      • 2020-11-24
      • 2016-07-21
      • 2020-04-23
      • 2019-05-12
      • 2016-05-23
      • 2014-09-08
      • 2019-01-07
      • 2021-06-14
      • 2021-06-23
      相关资源
      最近更新 更多