Django 查询 ManyToMany 字段中的记录总数



给定两个模型,由一个没有直通表的ManyToMany连接:

class Ingredient(models.Model):
    name = models.CharField(max_length=255)
class Recipe(models.Model):
    name = models.CharField(max_length=255)
    ingredients = models.ManyToManyField(Ingredient)

如何找到配方中使用的成分的实例总数?

例如,如果我有两种成分(苹果和糖(和两种食谱(苹果派和甜

甜圈(,我怎么知道食谱有 3 种用途(两种是因为苹果派使用苹果和糖,一种是因为甜甜圈使用糖(?

我可以用以下内容来做到这一点:

count = 0
for recipe in Recipe.objects.all():
  count += recipe.ingredients.count()

但这会产生太多查询。

有没有一种简单的方法可以通过注释/聚合来获取这个数字?

我们可以这样尝试(当然是为了避免很多DB命中。使用数据库聚合(。

from django.db.models import Count
recipes = Recipe.objects.annotate(count_ingredients=Count('ingredients'))
for recipe in recipes:
    print(recipe.pk, recipe.count_ingredients)
Recipe.ingredients.through.objects.filter(ingredient=YOUR_INGREDIENT_HERE).count()

Recipe.through是保存many_to_many字段对象的"秘密"表,一个新的 Recipe_ingredients(Django 的默认名称(对象被创建。如果您想使用使用给定成分的食谱数量,您可以使用您的成分过滤该表并获取其计数。

对于您的示例,将创建这些:(伪(

Recipe_ingredients(ingredient=sugar, recipe=apple_pie)
Recipe_ingredients(ingredient=sugar, recipe=doughnut)
Recipe_ingredients(ingredient=apple, recipe=apple_pie)

从这里您可以使用该表计算任何内容,如果您想知道所有成分的总用途,它就像

Recipe.ingredients.through.objects.count()
recipes = Recipe.objects.all()
for recipe in recipes:
    print(recipe.ingredient_set.count())

最新更新