如何用Django ORM实现含外键的Group By查询?
Django ORM 实现指定SQL查询
首先假设你的Django模型定义如下(对应题目中的数据库表结构):
from django.db import models class User(models.Model): id = models.AutoField(primary_key=True) display_name = models.CharField(max_length=255) # 其他业务字段... class Tournament(models.Model): id = models.AutoField(primary_key=True) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='tournaments') start_date = models.DateTimeField() # 其他业务字段...
你可以通过两种方式实现目标SQL:
方式一:从User模型出发查询
利用User模型的反向关联(tournaments是外键的related_name)过滤赛事时间,再统计每个用户的赛事数量:
from django.db.models import Count from django.utils import timezone # 执行查询 query_result = User.objects.filter( tournaments__start_date__date__gt=timezone.date(2022, 7, 1) ).annotate( tournament_count=Count('tournaments') ).values('id', 'display_name', 'tournament_count')
方式二:从Tournament模型出发查询
直接从赛事表过滤时间,按用户字段分组后统计数量,更贴近原SQL的逻辑:
from django.db.models import Count from django.utils import timezone # 执行查询 query_result = Tournament.objects.filter( start_date__date__gt=timezone.date(2022, 7, 1) ).values( 'user__id', 'user__display_name' ).annotate( tournament_count=Count('id') ).order_by('user__id', 'user__display_name')
注意事项:
- 如果
Tournament模型中外键的related_name未指定(默认是tournament_set),需要把方式一中的tournaments替换为tournament_set。 - 如果
start_date字段是DateField而非DateTimeField,则去掉查询中的__date,直接写start_date__gt=timezone.date(2022, 7, 1)。
内容的提问来源于stack exchange,提问作者pineforest22
相关产品推荐
相关产品推荐

