django Отношение ManyToMany при добавлении объектов выдает ошибку - PullRequest
0 голосов
/ 29 мая 2018

У меня есть объект 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, который имеет отношение ManyToMany с объектом UserAnalytics.

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, используя этот код,

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)

Это ошибка, которую я получаю, Traceback (последний вызов был последним):

 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'

Что я здесь не так делаю?

1 Ответ

0 голосов
/ 29 мая 2018

Я думаю, что вы отредактировали ошибку из своего поля зрения.

В трассировке показано, что в вашем файле api.py:28 есть строка:

feed.viewers.add(<b>user.analytics</b>)

Но user.analytics это единицаотношение-ко-многим, и, таким образом, один пользователь может иметь несколько UserAnalytics объектов (поскольку многие из них могут относиться к одному и тому же использованию).В результате user.analytics является не отдельным объектом или коллекцией, а RelatedManager: своего рода менеджером для управления связанными объектами.

Вы можете добавить .all()и выполните повторяемую распаковку , чтобы добавить все объекты .analytics за один вызов:

feed.viewers.add(<b>*user.analytics.all()</b>)

(обратите внимание на звездочку * в вызове).

Если у каждого пользователя не более одного UserAnalytics объекта, лучше использовать OneToOneField, поэтому:

# only in case a user has *at most* one UserAnalytics object
class UserAnalytics(models.Model):
    <b>user = models.OneToOneField(User, related_name='analytics', on_delete=models.CASCADE, null=True)</b>
    uptime = models.IntegerField(null=True)
    feeds_viewed = models.IntegerField(null=True)
    feeds_shared = models.IntegerField(null=True)

В этом случае user.analyics либо возвратит связанныйUserAnalytics объект (если он есть) или - если такого объекта нет - выдает ошибку UserAnalytics.DoesNotExist.

...