Как правильно отфильтровать отношения Many2Many / Generic с Q? - PullRequest
2 голосов
/ 27 апреля 2010

У меня есть 3 модели, у TaggedObject есть GenericRelation с ObjectTagBridge. И у ObjectTagBridge есть ForeignKey для модели тегов.

class TaggedObject(models.Model):
    """
        class that represent a tagged object
    """
    tags = generic.GenericRelation('ObjectTagBridge',
                                   blank=True, null=True)

class ObjectTagBridge(models.Model):
    """
        Help to connect a generic object to a Tag.
    """
    # pylint: disable-msg=W0232,R0903
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    tag = models.ForeignKey('Tag')

class Tag(models.Model):
    ...

когда я прикрепляю тег к объекту, я создаю новый объект ObjectTagBridge и присваиваю его тегу ForeignKey тег, который я хочу прикрепить. Это работает нормально, и я могу легко получить все теги, которые я прикрепил к моему объекту. Но когда я хочу получить (отфильтровать) все объекты, которые имеют Tag1 и Tag2, я попытался что-то вроде этого:

query = Q(tags__tag=Tag1) & Q(tags__tag=Tag2)
object_list = TaggedObjects.filter(query)

но теперь мой object_list пуст, потому что он ищет TaggedObjects, которые имеют один ObjectTagBridge с 2 объектами тега, первый с Tag1, а второй с Tag2.

В моем приложении будут более сложные Q-запросы, чем этот, поэтому я думаю, что мне нужно решение с этим Q-объектом. Фактически любая комбинация бинарных союзов, например: (...) and ( (...) or not(...))

Как я могу отфильтровать это правильно? Каждый ответ приветствуется, может быть, есть и другой способ добиться этого.

спасибо за помощь !!!

Ответы [ 2 ]

1 голос
/ 09 мая 2010

Если вы ищете результат TaggedObject с Tag1 и Tag2, рассмотрите возможность запроса TaggedObject вместо запроса ObjectTagBridge. Вот как может выглядеть этот запрос:

results = TaggedObject.objects.filter(objecttagbridge__tag = Tag1).filter(objecttagbridge__tag = Tag2)

По сути, мы проводим два фильтра. Только объекты с тегами Tag1 и Tag2 будут проходить критерии фильтрации и быть частью набора результатов.

0 голосов
/ 28 апреля 2010

Похоже, вы пытаетесь вручную реализовать таблицу «многие ко многим», а затем объединить ее с общим отношением. Лучшим подходом может быть позволить Django обработать M2M для вас и просто представить его в общих отношениях следующим образом:

class TaggedObject(models.Model):
    """
        Help to connect a generic object to a Tag.
    """
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    tags = models.ManyToManyField('Tag')

class Tag(models.Model):
    ...

Это должно позволить вам делать то, что вы пытались сделать ...

objects = TaggedObject.objects.filter(
    Q(tags=Tag1) & Q(tags=Tag2)
)
...