继承阻止 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
我一直在学习教程 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