如何使用Q正确过滤Many2Many / Generic Relations?

时间:2010-04-27 19:09:13

标签: django django-models django-q

我有3个模型,TaggedObject与ObjectTagBridge有一个GenericRelation。并且ObjectTagBridge对Tag模型有一个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):
    ...

当我将Tag附加到Object时,我正在创建一个新的ObjectTagBridge并将其ForeignKey标记设置为我想要附加的Tag。这工作正常,我可以很容易地获得我附加到我的对象的所有标签。但是当我想得到(过滤)所有具有Tag1和Tag2的对象时,我尝试过这样的事情:

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

但是现在我的object_list是空的,因为它正在寻找TaggedObjects,它有一个带有2个标签对象的ObjectTagBridge,第一个带有Tag1,第二个带有Tag2。

我的应用程序将是比这个更复杂的Q查询,所以我认为我需要一个有这个Q对象的解决方案。实际上是二元连词的任意组合,例如:(...) and ( (...) or not(...))

如何正确过滤?每个答案都是受欢迎的,也许还有不同的方法来实现这一目标。

谢谢你的帮助!!!

2 个答案:

答案 0 :(得分:1)

如果您要查找的结果是带有Tag1和Tag2的TaggedObject,请考虑查询TaggedObject而不是查询ObjectTagBridge。这就是查询的样子:

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

基本上我们正在进行两个过滤器。只有Tag1和Tag2的对象都将通过过滤条件并成为结果集的一部分。

答案 1 :(得分:0)

看起来您正在尝试手动实现“多对多”表,然后将其与通用关系相结合。一个更好的方法可能是让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)
)