2011-06-03 50 views
0

希望有人能帮助我解决这个问题。Django结合AND和OR查询ManyToMany字段

我想弄清楚我是否可以构建一个查询,允许我从我的数据库同时检索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对象来构建查询,以便在需要项目的多个字段(在此情况下是标记)中匹配多个值。以下查询:

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

提前感谢您对此有所帮助!

+0

您是否希望将两个条件'与AND连接'? – arustgi 2011-06-03 20:20:12

+0

嗨Arustgi,我实际上需要每个标准加入一个或。因此,继续上面的例子,我会寻找所有品牌(品牌='品牌')OR(tag_name ='80s'和tag__name ='喜剧') – 2011-06-03 21:44:19

回答

3

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

1

Django的过滤器自动和。 Q对象仅在您尝试添加OR时才需要。此外,__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) 

附:related_name值应始终指定相反的关系。您目前的做法会遇到逻辑问题。例如:

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

就是说somebrand.brand.all()实际上将返回Item对象。它应该是:

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

然后,您可以使用somebrand.items.all()获得品牌产品。更有意义。

+0

嘿克里斯,谢谢你的回应。我实际上是在我的实际代码中使用brand__in =品牌(这只是简化了上面的内容),因为我需要用两个标签标记的东西也构建标签查询,完全按照您在这里描述的方式进行。我坚持的是在单个查询中是否有办法做到这一点?物品=(品牌_in =品牌)或(关键字中的关键字:...)的逻辑上的东西?或者我必须将每个转换为列表并合并?也感谢有关related_name值的伟大建议 - 已经做出了改变。再次感谢! – 2011-06-03 22:00:23

+0

您可以根据需要多次过滤查询集;对数据库仍然只有一个查询。 Django查询集是懒惰的:他们直到你做了一些需要评估的事情才会真正评估,比如遍历它们的项目。 – 2011-06-06 14:24:48