2012-01-09 52 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