Reputation: 1652
So i have made a 'recipe' web application in Django, where i have a feature called "User's cabinet" in which user can add any of the ingredients and he would be presented with an option known as 'Makeable recipes', in which the application would suggest the user of which recipes he would be able to make given his cabinet's ingredients. Now the problem is if i want the recipes to contain any of the ingredients in the cabinet i can do 'Recipe.objects.filter(ingredients__in=cabinet_ingredients). And if i want to filter all of the ingredients in the cabinet, i can do:
qs = Recipe.objects.annotate(count=Count('ingredients'))\
.filter(count=len(cabinet_ingredients))
for ingredient in cabinet_ingredients:
qs = qs.filter(ingredients=ingredient)
But if i want a subset of the cabinet ingredients (which makes more sense) such that the recipes should not contain anything outside of these ingredients and can contain anything in this list. For example given the 3 cabinet ingredients, 'foo', 'bar', 'baz', i have to find the recipes with the following results:
Recipes with 3 ingredients:
('foo', 'bar', 'baz')
Recipes with 2 ingredients:
('foo', 'bar'),
('foo', 'baz'),
('bar', 'baz')
Recipes with single ingredient:
('foo')
('bar')
('baz')
Any clue to this? Thanks in advance.
Upvotes: 2
Views: 6453
Reputation: 239290
@cha0site's answer is mostly correct. However, that will result in two queries to the database, whereas only one is necessary. Use the following approach instead:
from django.db.models import Q
Recipe.objects.exclude(~Q(ingredients__name__in=cabinet_ingredients))
Upvotes: 0
Reputation: 10717
Assuming you have a table for ingredients, you can do something like:
# 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)
Upvotes: 4