В Django есть способ использовать FOO_set на модели с внешним ключом, который ссылается на объекты того же типа модели? - PullRequest
0 голосов
/ 02 ноября 2011

У меня есть такая модель:

    class Video(models.Model):
      views = models.ManyToManyField(User, null=True, related_name='views')
      parent = models.ForeignKey('self', null=True)

      def __unicode__(self):
        return self.title

      def _get_views_count(self):
        return self.views.count()

      def _get_comments_count(self):
        return self.comment_set.all().count()

      def _get_playlists(self):
        return self.playlist_set.all()

      views_count = property(_get_views_count)
      comments_count = property(_get_comments_count)
      playlists = property(_get_playlists)

      most_viewed_objects = MostViewedVideoManager()
      objects = models.Manager()



 class MostViewedVideoManager(models.Manager):
      def get_query_set(self):
        return super(MostViewedProjectManager, self).get_query_set().annotate(lovers=Count('views')).order_by('viewers')[:20]

И я хочу получить набор видео, которые имеют данного родителя. Я думал, что могу сделать что-то вроде этого:

v = Video.objects.get(id=3)
v.video_set.all()

Однако выдает эту ошибку:

AssertionError: Cannot filter a query once a slice has been taken.

    (full trace)
    /usr/local/lib/python2.7/dist-packages/django/db/models/manager.pyc in all(self)
    115 
    116     def all(self):
--> 117         return self.get_query_set()
    118 
    119     def count(self):

/usr/local/lib/python2.7/dist-packages/django/db/models/fields/related.pyc in get_query_set(self)
    421             def get_query_set(self):
    422                 db = self._db or router.db_for_read(rel_model, instance=instance)
--> 423                 return superclass.get_query_set(self).using(db).filter(**(self.core_filters))
    424 
    425             def add(self, *objs):

/usr/local/lib/python2.7/dist-packages/django/db/models/query.pyc in filter(self, *args, **kwargs)
    548         set.
    549         """
--> 550         return self._filter_or_exclude(False, *args, **kwargs)
    551 
    552     def exclude(self, *args, **kwargs):

/usr/local/lib/python2.7/dist-packages/django/db/models/query.pyc in _filter_or_exclude(self, negate, *args, **kwargs)
    560         if args or kwargs:
    561             assert self.query.can_filter(), \
--> 562                     "Cannot filter a query once a slice has been taken."
    563 
    564         clone = self._clone()

Я полагаю, что это связано с MostViewedManager - поскольку устранение этой проблемы решает проблему. Какой правильный способ сделать это?

Ответы [ 2 ]

2 голосов
/ 02 ноября 2011

Как говорится в сообщении об ошибке, вы пытаетесь отфильтровать набор запросов, который уже был разрезан.

Не возвращать нарезанный набор запросов из метода get_query_set менеджера. Либо верните его без среза, либо создайте отдельный метод, который возвращает нарезанную версию.

0 голосов
/ 01 ноября 2013

Это не решает вашу конкретную проблему (нарезанный набор запросов), но заголовок вашего сообщения указывает на то, что вы не знаете о related_name свойстве ForeignKey.

class Video(models.Model):
    views  = models.ManyToManyField(User, null=True, related_name='views')
    parent = models.ForeignKey('self', null=True, related_name='children')

Использование связанного имени позволяет выполнять более естественный запрос:

>>> video = Video.objects.get(id=1)
<Video: 1>
>>> video.children.all()
[<Video: 2>, <Video: 3>, <Video: 4>]
>>> gte2_lovers = Video.objects.annotate(lovers=count('views')).filter(lovers__gte=2)
>>> Video.objects.filter(children__in=gte2_lovers)
[<Video: 1>, <Video: 4>]
...