2010-04-30 68 views
1

我想要爲食譜數據庫建立一個前端,使用戶能夠搜索用戶提供的配料可烹飪的食譜列表。選擇在給定字符串中相關對象ID爲* all *的對象

我有以下型號

class Ingredient(models.Model): 
    name = models.CharField(max_length=100, unique=True) 
    slug = models.SlugField(max_length=100, unique=True) 
    importancy = models.PositiveSmallIntegerField(default=4) 
    […] 

class Amount(models.Model): 
    recipe = models.ForeignKey('Recipe') 
    ingredient = models.ForeignKey(Ingredient) 
    […] 

class Recipe(models.Model): 
    name = models.CharField(max_length=100) 
    slug = models.SlugField() 
    instructions = models.TextField() 
    ingredients = models.ManyToManyField(Ingredient, through=Amount) 
    […] 

和不正是我想要什麼rawquery:它讓所有包含在字符串的用戶提供的列表,其需要的成分所有的食譜。如果他提供的不是必要的話,那也沒關係。

query = "SELECT *, 
    COUNT(amount.zutat_id) AS selected_count_ingredients, 
    (SELECT COUNT(*) 
      FROM amount 
      WHERE amount.recipe_id = amount.id) 
    AS count_ingredients 
    FROM amount LEFT OUTER JOIN amount 
    ON (recipe.id = recipe.recipe_id) 
    WHERE amount.ingredient_id IN (%s) 
    GROUP BY amount.id 
    HAVING count_ingredients=selected_count_ingredients" % 
      ",".join([str(ingredient.id) for ingredient in ingredients]) 
recipes = Recipe.objects.raw(query) 

現在,我正在尋找的是一種不依賴於.raw(),因爲我想Django的queryset的方法去做純粹的方式。

此外,如果你們知道在查找中包含成分的重要性的方法,那麼即使其中一個成分(具有0的重要性)仍未顯示作爲結果的配方由用戶提供。

回答

1

看起來您爲此設置了模型做得非常好。您可以通過兩個非常簡單的查詢來完成,這可能會像使用連接的單個查詢一樣快。

amounts = Amount.objects.filter(ingredient__in=ingredients) 
rezepte = Rezept.objects.filter(
     pk__in=amounts.values_list('recipe', flat=True) 
    ).order_by('importancy') 

你甚至可以把它保存存儲到一個語句,如果你喜歡:

rezepte = Rezept.objects.filter(
     pk__in=Amount.objects.filter(
       ingredient__in=ingredients 
     ).values_list('recipe', flat=True) 
    ).order_by('importancy') 

無論是查詢應該自動地得到默認的索引出的Django的。您將得到兩個相當乾淨的查詢:

SELECT `yourproject_amount`.`recipe_id` FROM `yourproject_amount`; 
SELECT * FROM `yourproject_rezept` 
     WHERE `yourproject_rezept`.`id` IN (1, 2, 3, 4) 
     ORDER BY `yourproject_rezept`.`importancy`; 
+0

您的解決方案基本上是一個更快的版本'食譜= Recipe.objects.filter (ingredients__in =成分).distinct()'。但它甚至顯示只有一種配料與串的共同配方。我只想列出那些有**所有**的成分與繩子相同的人。 – jnns 2010-05-01 07:52:17

1

您可以使用possibleillity來連接查詢集。

最簡單的方法(但不是很有效,因爲在SQL加入量圖表不止一次,...):

ingredients = Ingredient.objects.filter(...) 
query = Recipe.object.all() 
for i in ingredients: 
    query = query.filter(ingredients=i) 


print query # at this database query will be exceuted 
+0

我可以看到一個解決方案,包含'annotate'和'filter'的組合: http://docs.djangoproject.com/en/dev/topics/db/aggregation/#order-of-annotate-and-filter-但是剩下的時間是短的....(結束1分鐘:-() – maersu 2010-05-10 17:43:01

+0

那麼,如果我有一個配方#1需要成分A,B和C和另一個配方#2,只需要A和B.用戶提供成分A和B,但不提供C,並且您的查詢將返回兩份食譜,其中只有第二份應該返回。 – jnns 2010-05-11 17:26:14