【问题标题】:How to filter Many2Many / Generic Relations properly with Q?如何使用 Q 正确过滤 Many2Many / Generic Relations?
【发布时间】:2011-02-13 00:44:18
【问题描述】:

我有 3 个模型,TaggedObject 与 ObjectTagBridge 有一个 GenericRelation。并且 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 是空的,因为它正在寻找具有一个 ObjectTagBridge 和 2 个标签对象的 TaggedObjects,第一个带有 Tag1,第二个带有 Tag2。

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

如何正确过滤?欢迎每个答案,也许还有其他方法可以实现这一目标。

感谢您的帮助!!!

【问题讨论】:

    标签: django django-models django-q


    【解决方案1】:

    如果您要查找的结果是带有 Tag1 和 Tag2 的 TaggedObject,请考虑查询 TaggedObject 而不是查询 ObjectTagBridge。该查询可能如下所示:

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

    基本上我们正在执行两个过滤器。只有同时具有 Tag1 和 Tag2 的对象才能通过过滤条件并成为结果集的一部分。

    【讨论】:

    • 是的,你是对的。我希望我可以用 Q 对象做到这一点。在这种情况下,我可以对不同的 TaggedObjects 使用相同的过滤器。我重写了我的 API 并以这种方式实现了它。 THX
    【解决方案2】:

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

    【讨论】:

    • 谢谢。但在我的情况下,我还需要将附加信息附加到标签 对象关系,所以我需要额外的表。这种方法的另一个优点是,我可以创建多个从 TaggedObject 继承的类,并且从 Tag 的视图来看,标记哪个 Object 没有区别。
    猜你喜欢
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    • 2020-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    相关资源
    最近更新 更多