我有一个UserAnalytics对象,它与用户有一对一的关系。
class UserAnalytics(models.Model):
user = models.ForeignKey(User, related_name='analytics', on_delete=models.CASCADE, null=True)
uptime = models.IntegerField(null=True)
feeds_viewed = models.IntegerField(null=True)
feeds_shared = models.IntegerField(null=True)
我有一个Feed对象,它与UserAnalytics对象具有ManyToMany关系。
class Feed(Base):
headline = models.CharField(max_length=255)
link = models.CharField(max_length=255, unique=True)
summary = models.TextField()
thumbnail = models.CharField(max_length=512, null=True)
published_date = models.DateTimeField()
views = models.IntegerField(default=0)
shares = models.IntegerField(default=0)
source = models.ForeignKey(Source, on_delete=models.CASCADE, null=True)
reader = models.ManyToManyField(User, through='Bookmark')
viewers = models.ManyToManyField(UserAnalytics)
当我尝试使用此代码向UserAnalytics添加Feed时,
class ReadFeed(views.APIView):
def get(self, request, **kwargs):
try:
user = User.objects.get(id=kwargs.get('user_id'))
analytics = UserAnalytics.objects.get(id=user.id)
except User.DoesNotExist:
return Response({"Error": "User does not exist"}, status=status.HTTP_404_NOT_FOUND)
try:
feed = Feed.objects.get(id=kwargs.get('feed_id'))
feed.views += 1
feed.viewers.add(analytics)
feed.save()
user.analytics.add(feed)
user.analytics.save()
return Response(FeedSerializer(feed).data, status=status.HTTP_200_OK)
except Feed.DoesNotExist:
return Response({"Error": "Feed does not exist"}, status=status.HTTP_404_NOT_FOUND)
这是我得到的错误, 回溯(最近一次调用最后一次):
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/views/generic/base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/rest_framework/views.py", line 494, in dispatch
response = self.handle_exception(exc)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/rest_framework/views.py", line 454, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/rest_framework/views.py", line 491, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/aggregator/api.py", line 28, in get
feed.viewers.add(user.analytics)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py", line 898, in add
self._add_items(self.source_field_name, self.target_field_name, *objs)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py", line 1045, in _add_items
'%s__in' % target_field_name: new_ids,
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/query.py", line 836, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/query.py", line 854, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1253, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1277, in _add_q
split_subq=split_subq,
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1215, in build_filter
condition = self.build_lookup(lookups, col, value)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1085, in build_lookup
lookup = lookup_class(lhs, rhs)
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/lookups.py", line 18, in __init__
self.rhs = self.get_prep_lookup()
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/fields/related_lookups.py", line 59, in get_prep_lookup
self.rhs = [target_field.get_prep_value(v) for v in self.rhs]
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/fields/related_lookups.py", line 59, in <listcomp>
self.rhs = [target_field.get_prep_value(v) for v in self.rhs]
File "/Users/mstewart/Dropbox/xdrive/ftb/ftb_core_backend/env/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 947, in get_prep_value
return int(value)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'RelatedManager'
[28/May/2018 15:55:19] "GET /api/v1/aggregator/read/4/67 HTTP/1.1" 500 18150
TypeError: int() argument must be a string, a bytes-like object or a number, not 'RelatedManager'
我在这里做错了什么?
答案 0 :(得分:3)
我认为您已经在视图中编辑了错误。
回溯显示您的文件api.py:28
有一行:
feed.viewers.add(user.analytics)
但是user.analytics
是一对多的关系,因此一个用户可以拥有多个UserAnalytics
个对象(因为其中许多都可以引用相同的用法)。因此,user.analytics
不单个对象,也不是集合,而是RelatedManager
:某种管理相关对象的管理器。
您可以添加.all()
并执行 iterable unpacking ,只需一次调用即可添加所有.analytics
个对象:
feed.viewers.add(*user.analytics.all())
(注意通话中的星号*
。)
如果每个用户最多只有一个 UserAnalytics
个对象,最好使用OneToOneField
,所以:
# only in case a user has *at most* one UserAnalytics object
class UserAnalytics(models.Model):
user = models.OneToOneField(User, related_name='analytics', on_delete=models.CASCADE, null=True)
uptime = models.IntegerField(null=True)
feeds_viewed = models.IntegerField(null=True)
feeds_shared = models.IntegerField(null=True)
在这种情况下,user.analyics
将返回关联的UserAnalytics
对象(假设有一个),或者 - 如果没有这样的对象 - 引发UserAnalytics.DoesNotExist
错误。