Django将AND和OR查询与ManyToMany字段组​​合在一起

时间:2011-06-03 18:03:29

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

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

我正在试图弄清楚是否可以构建一个查询,允许我同时根据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. 用户关注的用户上传的项目(在模型中称为“品牌”)。因此,例如,如果用户关注Paramount用户帐户,我希望所有商品都在品牌=派拉蒙。

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

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

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

    对于#2(基于文档):

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

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

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

    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

    先谢谢你的帮助!

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

Django自动过滤AND。只有在您尝试添加OR时才需要Q个对象。此外,__in查询过滤器将为您提供帮助。

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

`brand__in=brands`

brands是由someuser.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()获取品牌商品。更有意义。