继承阻止 Django-rest-framework 的魔力:'User' 对象没有属性 'mage'

Inheritance blocking Django-rest-framework's mojo: 'User' object has no attribute 'mage'

我一直在学习教程 here,除了我没有创建代码片段网络工具,我正在创建 RPG 角色管理器,我一直在换掉'snippet' 和 'mage'。另一个主要区别是我的法师仅通过其超类 NWODCharacter 保留用户(这样我以后可以添加其他角色类型,如狼人和吸血鬼!)

在访问 http://localhost:8000/users/ 时出现此错误:

AttributeError at /users/
'User' object has no attribute 'mages'

Environment: 

Request Method: GET
Request URL: http://localhost:8000/users/

Django Version: 1.7.1
Python Version: 3.4.2
Installed Applications:
('autocomplete_light',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'characters')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware')


Traceback:
File "C:\Python34\lib\site-packages\django\core\handlers\base.py" in get_response
  111.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Python34\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view
  57.         return view_func(*args, **kwargs)
File "C:\Python34\lib\site-packages\django\views\generic\base.py" in view
  69.             return self.dispatch(request, *args, **kwargs)
File "C:\Python34\lib\site-packages\rest_framework\views.py" in dispatch
  407.             response = self.handle_exception(exc)
File "C:\Python34\lib\site-packages\rest_framework\views.py" in dispatch
  404.             response = handler(request, *args, **kwargs)
File "C:\Python34\lib\site-packages\rest_framework\generics.py" in get
  269.         return self.list(request, *args, **kwargs)
File "C:\Python34\lib\site-packages\rest_framework\mixins.py" in list
  46.         return Response(serializer.data)
File "C:\Python34\lib\site-packages\rest_framework\serializers.py" in data
  615.         ret = super(ListSerializer, self).data
File "C:\Python34\lib\site-packages\rest_framework\serializers.py" in data
  212.                 self._data = self.to_representation(self.instance)
File "C:\Python34\lib\site-packages\rest_framework\serializers.py" in to_representation
  565.             self.child.to_representation(item) for item in iterable
File "C:\Python34\lib\site-packages\rest_framework\serializers.py" in <listcomp>
  565.             self.child.to_representation(item) for item in iterable
File "C:\Python34\lib\site-packages\rest_framework\serializers.py" in to_representation
  423.                 attribute = field.get_attribute(instance)
File "C:\Python34\lib\site-packages\rest_framework\relations.py" in get_attribute
  350.         relationship = get_attribute(instance, self.source_attrs)
File "C:\Python34\lib\site-packages\rest_framework\fields.py" in get_attribute
  69.                 instance = getattr(instance, attr)

Exception Type: AttributeError at /users/
Exception Value: 'User' object has no attribute 'mages'

它看起来取决于这样一个事实,即我的 Mage 模型持有到 django 定义的 FK User,并且 django-rest-frameworks 需要做一些魔术来连接两者向上。但是我使用继承的事实在某种程度上阻碍了 django-rest-frameworks mojo。

所以我的模型看起来像:

class NWODCharacter(models.Model):

    class Meta:
        abstract = True
    SUB_RACE_CHOICES = ()
    FACTION_CHOICES = ()

    name = models.CharField(max_length=200)
    player = models.ForeignKey('auth.User')
    created_date = models.DateTimeField(auto_now_add=True, auto_now=False)
    updated_date = models.DateTimeField(auto_now_add=False, auto_now=True)
    published_date = models.DateTimeField(blank=True, null=True)
    sub_race = models.CharField(choices=SUB_RACE_CHOICES, max_length=50)
    faction = models.CharField(
        choices=FACTION_CHOICES, max_length=50, null=True)


class Characteristics(models.Model):

    class Meta:
        abstract = True
    VIRTUE_CHOICES = (('prudence', 'Prudence'), ('justice', 'Justice'),
                      ('temperance', 'Temperance'), ('fortitude',
                                                     'Fortitude'), ('faith', 'Faith'),
                      ('hope', 'Hope'), ('charity', 'Charity'))
    VICE_CHOICES = (('lust', 'Lust'), ('gluttony', 'Gluttony'), ('greed', 'Greed'),
                    ('sloth', 'Sloth'), ('wrath', 'Wrath'), ('envy', 'Envy'), ('pride', 'Pride'))

    power_level = IntegerRangeField(min_value=1, max_value=10, default=1)
    energy_trait = IntegerRangeField(min_value=1, max_value=10, default=7)
    virtue = models.CharField(choices=VIRTUE_CHOICES, max_length=50)
    vice = models.CharField(choices=VICE_CHOICES, max_length=50)
    morality = IntegerRangeField(min_value=0, max_value=10, default=7)
    size = IntegerRangeField(min_value=1, max_value=10, default=5)

class Mage(NWODCharacter, Characteristics):

    def __str__(self):
        return self.name

我的序列化器是这样的:

class MageSerializer(serializers.ModelSerializer):
    player = serializers.ReadOnlyField(source='player.username')

    class Meta:
        model = Mage
        fields = ('id', 'player', 'name', 'created_date', 'updated_date', 'published_date',
                  'sub_race', 'faction', 'power_level', 'energy_trait', 'virtue', 'vice', 'morality', 'size',)


class UserSerializer(serializers.ModelSerializer):
    mages = serializers.PrimaryKeyRelatedField(
        many=True, queryset=Mage.objects.all())

    class Meta:
        model = User
        fields = ('id', 'username', 'mages')

以上是我的简单看法

class MageList(generics.ListCreateAPIView):
    queryset = Mage.objects.all()
    serializer_class = MageSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(player=self.request.user)


class MageDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Mage.objects.all()
    serializer_class = MageSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)


class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

我该如何解决这个差异?

您需要使用相关名称才能从用户那里访问法师。
但在您的情况下,您使用的是摘要 class。

您需要像这样更改您的外键 player :
player = models.ForeignKey('auth.User', related_name="%(class)s_by_user")

然后在序列化程序中使用该相关名称:

class UserSerializer(serializers.ModelSerializer):
    mage_by_user = serializers.PrimaryKeyRelatedField(
        many=True, queryset=Mage.objects.all())

    class Meta:
        model = User
        fields = ('id', 'username', 'mage_by_user')

在此处阅读更多相关信息:https://docs.djangoproject.com/en/3.0/topics/db/models/#abstract-related-name