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

ぐ巨炮叔叔 提交于 2020-01-03 05:23:11

问题


I've been following the tutorial here, except as I'm not creating a code snippet web-tool, I'm creating a RPG character manager, I've been swapping out 'snippet' with 'mage'. The other major difference is that my Mage only has a hold of users via their superclass NWODCharacter (this is so I can later on add other character types, like Werewolves and Vampires!)

On accessing http://localhost:8000/users/ I get this error:

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'

It looks like it hinges on the fact that, my Mage model holds a FK to the django defined User, and django-rest-frameworks needs to do some magic to connect the two up. But the fact that I'm using inheritance is somehow blocking django-rest-frameworks mojo.

So my model looks like:

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

And my serializers appear like so:

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')

And these are my simple views

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

How do I work round this difference?


回答1:


You need to use the related name to access mages from the user.
But in your case, you're using an abstract class.

You need to change your foreign key player like so :
player = models.ForeignKey('auth.User', related_name="%(class)s_by_user")

And then use that related name in your serializer :

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')

Read more about this here :
https://docs.djangoproject.com/en/1.7/topics/db/models/#be-careful-with-related-name



来源:https://stackoverflow.com/questions/28430881/inheritance-blocking-django-rest-frameworks-mojo-user-object-has-no-attribut

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!