Django查询ForeignKey Count()为零

时间:2017-10-19 20:28:20

标签: django django-queryset

我有3张桌子:

卡车,其中包含以下字段:idname ....

菜单,其中包含以下字段:iditemnameid_foodtypeid_truck ...

食物类型,字段为:idtype ...

我希望得到如下摘要:

id  name              total
10  Alcoholic drink   0
5   Appetizer         11

我的问题是使用0元素返回结果。

我尝试了这样的SQL查询:

SELECT
    ft.id, ft.name, COUNT(me.id) total
FROM
    foodtype ft LEFT JOIN menu me
        ON ft.id = me.id_foodtype
    LEFT JOIN truck tr
        ON tr.id = me.id_truck AND tr.id = 3
GROUP BY ft.id, ft.name
ORDER BY ft.name

或Django中的查询

Menu.objects.filter(id_truck=3).values("id_foodtype").annotate(cnt=Count("id_foodtype"))

但是,它们都没有用Zero元素显示结果。

目前,要将此查询转换为Python代码,我的任何查询都会返回我预期的确切结果。 如何使用Left Join返回foodtypes的结果,包括menu中包含零元素的Employee1

1 个答案:

答案 0 :(得分:1)

LEFT JOIN的方向取决于您启动查询的对象。如果它从Menu开始,您将永远不会看到所选菜单项未使用FoodType。然后重要的是过滤(在你的情况下通过卡车)这样的方式,也允许空值Menu.id,以便可以获得Count == 0.

from django.db.models import Q
qs = (
    FoodType.objects
    .filter(Q(menu_set__id_truck=3) | Q(menu_set__id__isnull=True))
    .values()   # not necessary, but useful if you want a dict, not a Model object
    .annotate(cnt=models.Count("menu_set__id"))
)

验证

>>> print(str(qs.query))
SELECT foodtype.id, foodtype..., COUNT(menu.id) AS cnt
FROM foodtype
LEFT OUTER JOIN menu ON (foodtype.id = menu.id_foodtype)
WHERE _menu.id_truck = 3 OR menu.id IS NULL)
GROUP BY foodtype.id

它适用于当前最新和最旧的Django 2.0b1和1.8。

无论是否有.values()行,查询都是相同的。结果是带有cnt属性的字典或FoodType对象。

<强>脚注
如果您已定义related_name,则名称menu_set应替换为外键related_name的真实id_foodtype

class Menu(models.Model):
    id_foodtype = models.ForeignKey('FoodType', on_delete=models.DO_NOTHING,
                                    db_column='id_foodtype', related_name='menu_set'))
    ...

如果你开始一个新项目,我建议将外键重命名为不带“id”的名称,db_column字段带有“id”。然后menu_item.foodtype是食物对象,menu_item.id_foodtypeid