2012-01-09 126 views
2

所以我在Django中创建了一个'recipe'web应用程序,在那里我有一个名为“User's cabinet”的功能,用户可以在其中添加任何成分,提供一种称为“可制作食谱”的选项,其中应用程序将建议用户根据其内阁的成分能够制作哪些食谱。现在的问题是,如果我想让食谱中包含任何食材的成分,我可以做'Recipe.objects.filter(ingredients__in = cabinet_ingredients)。如果我想过滤所有机柜中的成分,我可以这样做:过滤django queryset只包含给定列表中的结果

qs = Recipe.objects.annotate(count=Count('ingredients'))\ 
       .filter(count=len(cabinet_ingredients)) 
for ingredient in cabinet_ingredients: 
    qs = qs.filter(ingredients=ingredient) 

但是如果我想机柜成分(这更有意义)的一个子集,使得配方不应该包含以外的任何东西这些成分可以包含任何东西在这个列表中。例如,给定3种内阁成分,“富”,“酒吧”,“巴兹”,我一定要找到,结果如下配方:

Recipes with 3 ingredients: 
('foo', 'bar', 'baz') 
Recipes with 2 ingredients: 
('foo', 'bar'), 
('foo', 'baz'), 
('bar', 'baz') 
Recipes with single ingredient: 
('foo') 
('bar') 
('baz') 

任何线索吗?提前致谢。

回答

3

假设你有成分的表,你可以这样做:

# ingredients _not_ in the cabinet 
inner_qs = Ingredient.objects.exclude(name__in = cabinet_ingredients) 
# recipes that do not contain an ingredient that is _not_ in the cabinet 
qs = Recipe.objects.exclude(ingredients__in = inner_qs) 
+0

感谢一吨,作品像一个魅力:) – tejinderss 2012-01-10 06:49:06

+0

太棒了!作为附录,您可能想阅读['in'字段查找文档](https://docs.djangoproject.com/en/1.3/ref/models/querysets/#in),尤其是_Performance_ _considerations_部分底部。 – cha0site 2012-01-10 10:42:25

0

@ cha0site的答案是正确的大部分。但是,这将导致对数据库的两个查询,而只有一个是必要的。改为使用以下方法:

from django.db.models import Q 
Recipe.objects.exclude(~Q(ingredients__name__in=cabinet_ingredients)) 
+0

嘿,根据文档,它会产生一个嵌套的查询,它可能会被数据库优化。我考虑过使用Q对象,但是不会和原来的'Recipe.objects.filter(ingredients__in = cabinet_ingredients)'完全一样吗?或者我在逻辑中遗漏了什么? – cha0site 2012-01-09 19:28:22

+0

Django可能会在相同的请求中发送内部查询以及外部查询。如果是这样的话,那么任何一种方法都可能同样有效。然而,'filter'实际上是不同的。使用您的版本和我的版本,我们明确排除不在列表中的任何内容,而您的评论中的“过滤器”仅包含任何具有这些成分的内容,无论它们是否还有其他1000种成分不在该列表中。 – 2012-01-09 19:42:39

+0

我不知道,但为什么这个方法给出了不同的结果比由cha0site发布的结果不同。 – tejinderss 2012-01-10 06:47:49