问题
I have 3 tables:
Truck with the fields: id
, name
....
Menu with the fields: id
, itemname
, id_foodtype
, id_truck
...
Foodtype with the fields: id
, type
...
I want to get a summary like:
id name total
10 Alcoholic drink 0
5 Appetizer 11
My problem is to return the results with 0
elements.
I tried an SQL query like this:
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
or a query in Django
Menu.objects.filter(id_truck=3).values("id_foodtype").annotate(cnt=Count("id_foodtype"))
But, neither is displaying the results with Zero
elements.
At the moment to convert this query to Python
code, any of my queries return the exact result that I expected.
How can I return results with the Left Join
including the foodtypes
with zero elements in the menu
?
回答1:
The direction of LEFT JOIN depends on the object, where you start the query. If it start on Menu
you will never see a FoodType
unused by selected Menu items. Then is important to filter (by Truck in your case) such way that also null value Menu.id is allowed in order to can get 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"))
)
Verify:
>>> 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
It works with the current newest and oldest Django 2.0b1 and 1.8.
The query is the same with or without the line .values()
. The results are dictionaries or FoodType objects with a cnt
attribute.
Footnotes:
The name menu_set
should be replaced by the real related_name
of foreign key id_foodtype
if you have defined the related_name.
class Menu(models.Model):
id_foodtype = models.ForeignKey('FoodType', on_delete=models.DO_NOTHING,
db_column='id_foodtype', related_name='menu_set'))
...
If you start a new project I recommend to rename the foreign key to a name without "id" and the db_column field is with "id". Then menu_item.foodtype
is a Food object and menu_item.id_foodtype
its id
.
来源:https://stackoverflow.com/questions/46838375/django-query-foreignkey-count-zero