混合Django Rest Framework中序列化器之间的公共字段

Pur*_*ret 8 python django mixins django-rest-framework

我有这个:

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
Run Code Online (Sandbox Code Playgroud)

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

我希望我的Mage Serializer能够在所有类型的角色之间使用'混合'而不是c/p(Mage是一种角色),希望这会增加我的webapp中的DRY.

问题在于我有这个模型:

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')
Run Code Online (Sandbox Code Playgroud)

这意味着我收到此错误:

TypeError at /characters/api/mages
<django.contrib.contenttypes.fields.create_generic_related_manager.<locals>.GenericRelatedObjectManager object at 0x00000000051CBD30> is not JSON serializable
Run Code Online (Sandbox Code Playgroud)

Django Rest Framework认为我想序列化我的通用关系.

如果我重命名模型(s/attributes/foos/g,s/skills/bars/g)中的字段,那么我得到一个不同的(不太清楚?)错误:

ImproperlyConfigured at /characters/api/mages
Field name `attributes` is not valid for model `ModelBase`.
Run Code Online (Sandbox Code Playgroud)

如何在不混淆DRF的情况下将这些方法和字段拖入混合中?

Nik*_*nyh 18

解决方案很简单

class GenericCharacterFieldMixin():
Run Code Online (Sandbox Code Playgroud)

class GenericCharacterFieldMixin(serializers.Serializer):
Run Code Online (Sandbox Code Playgroud)


tbi*_*tai 18

设置SerializerMetaclass

from rest_framework import serializers

class GenericCharacterFieldMixin(metaclass=serializers.SerializerMetaclass):
    # ...
Run Code Online (Sandbox Code Playgroud)

这是DRF 的作者推荐的解决方案。

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

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