Tricky Django GenericRelation запрос - PullRequest
2 голосов
/ 27 июня 2010

Предположим, у меня есть несколько моделей, представляющих объекты реальной жизни: " Человек ", " Стул ", " Комната "

У меня также есть модель " Collection ", которая представляет некоторую коллекцию записей этих моделей.

Каждая модель может быть членом более чем коллекции - поэтому я также создал модель " Membership ", которая представляет объект, являющийся членом коллекции. Он определяется следующим образом:

class Membership(models.Model):
   content_type   = models.ForeignKey(ContentType)
   object_id      = models.PositiveIntegerField()
   content_object = generic.GenericForeignKey('content_type', 'object_id')

   collection     = models.ForeignKey('Collection', related_name="members")

Я хочу иметь возможность создать QuerySet , который для данной коллекции представляет всех ее членов для данной модели . Я знаю, что могу сделать это программно, но мне нужно это в QuerySet, который можно фильтровать, заказывать и т. Д.

EDIT:

Очевидно, что это можно сделать с помощью необработанного SQL:

   SELECT * FROM 
       ( modelx INNER JOIN membership ON modelx.id = membership.object_id) 
   WHERE 
       ( membership.collection_id=<my-collection-id> AND    
         membership.content_type_id=<modelx-type-id> )

Но можно ли это представить с помощью языка запросов Django?

Ответы [ 3 ]

2 голосов
/ 01 июля 2010

Кажется, я нашел решение, используя QuerySet метод extra:

def members_of_model(collection,cls):
    cls_type = ContentType.objects.get_for_model(cls)
    cm_tablename = CollectionMembership._meta.db_table
    cls_tablename = cls._meta.db_table
    return cls.objects.all().extra(tables=[cm_tablename],
                                   where=[ '%s.content_type_id=%%s' % cm_tablename,
                                           '%s.collection_id=%%s' % cm_tablename,
                                           '%s.object_id=%s.id' % (cm_tablename, cls_tablename) ],
                                   params=[cls_type.id,collection.id] )

Возвращает действительный QuerySet конкретной модели, который содержит все записи, которые являются членамиконкретная коллекция.

1 голос
/ 28 июня 2010

Я реализовал именно это с помощью метода with_model в пользовательском менеджере для модели членства:

class CollectionMemberManager(models.Manager):
    use_for_related_fields = True

    def with_model(self, model):
        return model._default_manager.filter(pk__in=self.filter(member_content_type=ContentType.objects.get_for_model(model)).values_list('member_object_id', flat=True))

CollectionMember - мой эквивалент вашей Membership модели. Для получения дополнительной информации см. код полностью .

0 голосов
/ 27 июня 2010

Нет, это невозможно. Наборы запросов могут быть только одного типа модели. Таким образом, вы можете получить набор запросов из Membership объектов и обратиться к каждому свойству content_object, которое даст вам связанный объект, но вы не можете получить все связанные объекты непосредственно в одном наборе запросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...