【问题标题】:Mixin common fields between serializers in Django Rest FrameworkDjango Rest Framework 中序列化程序之间的 Mixin 公共字段
【发布时间】:2015-04-29 03:03:12
【问题描述】:

我有这个:

class GenericCharacterFieldMixin():
    attributes = serializers.SerializerMethodField('character_attribute')
    skills = serializers.SerializerMethodField('character_skill')

    def character_attribute(self, obj):
        character_attribute_fields = {}
        character_attribute_fields['mental'] = {str(trait_item.get()): trait_item.get().current_value
                                                for trait_item in obj.mental_attributes}
        character_attribute_fields['physical'] = {str(trait_item.get()): trait_item.get().current_value
                                                  for trait_item in obj.physical_attributes}
        character_attribute_fields['social'] = {str(trait_item.get()): trait_item.get().current_value
                                                for trait_item in obj.social_attributes}
        return character_attribute_fields

    def character_skill(self, obj):
        character_skill_fields = {}
        character_skill_fields['mental'] = {str(trait_item.get()): trait_item.get().current_value
                                            for trait_item in obj.mental_skills}
        character_skill_fields['physical'] = {str(trait_item.get()): trait_item.get().current_value
                                              for trait_item in obj.physical_skills}
        character_skill_fields['social'] = {str(trait_item.get()): trait_item.get().current_value
                                            for trait_item in obj.social_skills}
        return character_skill_fields


class MageSerializer(GenericCharacterFieldMixin, serializers.ModelSerializer):
    player = serializers.ReadOnlyField(source='player.username')
    arcana = serializers.SerializerMethodField()

    def get_arcana(self, obj):
        if obj:
            return {str(arcana): arcana.current_value for arcana in obj.linked_arcana.all()}

    class Meta:
        model = Mage
        fields = ('id', 'player', 'name', 'sub_race', 'faction', 'is_published',
                  'power_level', 'energy_trait', 'virtue', 'vice', 'morality', 'size',
                  'arcana', 'attributes', 'skills')
        depth = 1

GenericCharacterFieldMixin 是字符字段的混合,它是通用的,即对所有类型的字符都通用。

我希望我的 Mage Serializer 将这些“混合”而不是 c/p 然后在所有类型的字符之间(Mage 是一种字符)希望这会增加我的 web 应用程序的 DRYness。

问题出在我的模型上:

class NWODCharacter(models.Model):

    class Meta:
        abstract = True
        ordering = ['updated_date', 'created_date']

    name = models.CharField(max_length=200)
    player = models.ForeignKey('auth.User', related_name="%(class)s_by_user")
    ....

    def save(self, *args, **kwargs):
        ...

    attributes = GenericRelation('CharacterAttributeLink')
    skills = GenericRelation('CharacterSkillLink')

这意味着我收到此错误:

TypeError at /characters/api/mages
<django.contrib.contenttypes.fields.create_generic_related_manager.<locals>.GenericRelatedObjectManager object at 0x00000000051CBD30> is not JSON serializable

Django Rest Framework 认为我想序列化我的泛型关系。

如果我重命名模型中的字段(s/attributes/foos/gs/skills/bars/g),则会出现不同的(不太清楚?)错误:

ImproperlyConfigured at /characters/api/mages
Field name `attributes` is not valid for model `ModelBase`.

如何在不混淆 DRF 的情况下将这些方法和字段提取到 mixin 中?

【问题讨论】:

    标签: python django django-rest-framework mixins


    【解决方案1】:

    设置SerializerMetaclass:

    from rest_framework import serializers
    
    class GenericCharacterFieldMixin(metaclass=serializers.SerializerMetaclass):
        # ...
    

    这是解决方案recommended by DRF's authors

    前面的答案中建议的解决方案是有问题的:

    1. user1376455 的解决方案破解 DRF 以在 _declared_fields 中注册 mixin 的字段,方法是将子字段声明为不同的字段。此 hack 可能不适用于框架的后续版本。
    2. Nikolay Fominyh 的解决方案将 mixin 更改为完全成熟的序列化程序(请注意,因此,名称 GenericCharacterFieldMixin 对于不是 mixin 而是序列化程序的类来说非常不幸!)。这是有问题的,因为它将完整的 Serializer 类带入多重继承,请参阅 DRF issue 以了解为什么这是一个坏主意的示例。

    【讨论】:

      【解决方案2】:

      解决方法很简单

      class GenericCharacterFieldMixin():
      

      class GenericCharacterFieldMixin(serializers.Serializer):
      

      【讨论】:

      • 这是新事物吗?
      • @Pureferret,这是对问题的简短回答。我今天遇到了同样的问题,发现这个解决方案比 user1376455 答案更干净。
      【解决方案3】:

      我有同样的问题,我的谷歌搜索把我带到了这里。我设法解决了。 由于您在序列化器中包含属性和技能字段,因此您需要为其提供序列化方法。

      这对我有用

      class MageSerializer(GenericCharacterFieldMixin, serializers.ModelSerializer):
          player = serializers.ReadOnlyField(source='player.username')
          arcana = serializers.SerializerMethodField()
      
      
          attributes = serializers.PrimaryKeyRelatedField(many=True, 
                                      read_only= True)
          skills = serializers.PrimaryKeyRelatedField(many=True, 
                                      read_only= True)
      
      
          def get_arcana(self, obj):
            if obj:
              return {str(arcana): arcana.current_value for arcana in obj.linked_arcana.all()}
      
          class Meta:
              model = Mage
              fields = ('id', 'player', 'name', 'sub_race', 'faction', 'is_published',
                        'power_level', 'energy_trait', 'virtue', 'vice', 'morality', 'size',
                        'arcana', 'attributes', 'skills')
              depth = 1
      

      【讨论】:

        猜你喜欢
        • 2013-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-07
        • 2020-01-19
        • 2016-01-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多