【问题标题】:Django Combining AND and OR Queries with ManyToMany FieldDjango将AND和OR查询与ManyToMany字段相结合
【发布时间】:2011-09-08 00:33:03
【问题描述】:

希望有人可以帮助我解决这个问题。

我正在尝试确定是否可以构建一个查询,该查询允许我同时基于 ForeignKey 字段和 ManyToManyField 从我的数据库中检索项目。具有挑战性的部分是它需要过滤多个 ManyToMany 对象。

一个例子有望使这一点更清楚。这是我的(简化的)模型:

class Item(models.Model):
    name = models.CharField(max_length=200)
    brand = models.ForeignKey(User, related_name='brand')
    tags = models.ManyToManyField(Tag, blank=True, null=True)
    def __unicode__(self):
        return self.name
    class Meta:
        ordering = ['-id']

class Tag(models.Model):
    name = models.CharField(max_length=64, unique=True)
    def __unicode__(self):
        return self.name

我想构建一个基于两个条件检索项目的查询:

  1. 用户所关注的用户上传的项目(在模型中称为“品牌”)。因此,例如,如果用户正在关注派拉蒙用户帐户,我会想要品牌 = 派拉蒙的所有项目。

  2. 与已保存搜索中的关键字匹配的项目。例如,用户可以进行并保存以下搜索:“80 年代喜剧”。在这种情况下,我想要标签同时包含“80 年代”和“喜剧”的所有项目。

现在我知道如何为每个独立构建查询了。对于 #1,它是:

items = Item.objects.filter(brand=brand)

对于#2(基于文档):

items = Item.objects.filter(tags__name='80s').filter(tags__name='comedy')

我的问题是:是否可以将其构建为单个查询,这样我就不必将每个查询转换为列表、加入它们并删除重复项?

挑战似乎是没有办法使用 Q 对象来构造查询,您需要一个项目的 manytomany 字段(在本例中为标签)来匹配多个值。以下查询:

items = Item.objects.filter(Q(tags__name='80s') & Q(tags__name='comedy')) 

不起作用。

(参见:https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships

在此先感谢您的帮助!

【问题讨论】:

  • 您希望将这两个条件“与 AND 连接”吗?
  • 嗨,Arustgi,我实际上需要将每个条件与 OR 连接起来。因此,继续上面的示例,我将查找所有具有 (brand='brand') 或 (tag__name='80s' 和 tag__name='comedy') 的项目

标签: mysql django many-to-many django-queryset


【解决方案1】:

经过大量研究,我找不到将其组合成单个查询的方法,因此我最终将 QuerySet 转换为列表并将它们组合起来。

【讨论】:

    【解决方案2】:

    Django 的过滤器自动与。 Q 对象仅在您尝试添加 OR 时才需要。此外,__in 查询过滤器将帮助您很多。

    假设用户有多个他们喜欢的品牌,并且您想退回他们喜欢的任何品牌,您应该使用:

    `brand__in=brands`
    

    brandssomeuser.brands.all() 之类返回的查询集。

    同样可以用于您的搜索参数:

    `tags__name__in=['80s','comedy']`
    

    这将返回带有“80 年代”或“喜剧”标签的内容。如果您需要两者(同时标记为“80 年代”和“喜剧”的事物),则必须在连续的过滤器中传递每一个:

    keywords = ['80s','comedy']
    for keyword in keywords:
        qs = qs.filter(tags__name=keyword)
    

    P.S. related_name 值应始终指定相反的关系。您当前的操作方式将遇到逻辑问题。例如:

    brand = models.ForeignKey(User, related_name='brand')
    

    意味着somebrand.brand.all() 实际上会返回Item 对象。应该是:

    brand = models.ForeignKey(User, related_name='items')
    

    然后,您可以通过somebrand.items.all() 获取品牌商品。更有意义。

    【讨论】:

    • 嗨,克里斯,感谢您的回复。我实际上在我的实际代码中使用了brand__in=brands(只是在上面进行了简化),并且由于我需要用两个标签标记的东西,所以我也完全按照您在此处描述的那样构建标签查询。我坚持的是是否有办法在一个查询中同时完成这两项工作?逻辑上类似于 items = (brands__in=brands) OR (forkeyword in keywords:...) 的东西?还是我必须将每个转换为列表并合并?还要感谢有关 related_name 值的好建议 - 已经进行了更改。再次感谢!
    • 您可以根据需要多次过滤查询集;对数据库仍然只有一个查询。 Django 查询集是惰性的:它们实际上不会进行评估,除非您对它们进行需要评估的操作,例如迭代它们的项目。
    猜你喜欢
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-28
    • 2012-10-27
    • 2012-11-03
    相关资源
    最近更新 更多