Django按科目、主题分组统计问题数并替换ID为名称
问题描述
我有三个Django模型,结构如下:
class Subject(models.Model): subject = models.CharField(max_length=200, unique=True) class Topic(models.Model): subject = models.ForeignKey(Subject, on_delete=models.CASCADE) topic = models.CharField(max_length=200, blank=False) class Question(models.Model): subject = models.ForeignKey(Subject, on_delete=models.CASCADE) topic = ChainedForeignKey( "Topic", chained_field="subject", chained_model_field="subject", show_all=False, auto_choose=True, )
我需要创建查询,按科目、主题分组统计每个组的问题ID数量,期望输出如下:
╔═════════╤═══════╤═══════╗ ║ subject │ topic │ count ║ ╠═════════╪═══════╪═══════╣ ║ 1 │ 1 │ 10 ║ ╟─────────┼───────┼───────╢ ║ 1 │ 2 │ 11 ║ ╟─────────┼───────┼───────╢ ║ 2 │ 3 │ 5 ║ ╟─────────┼───────┼───────╢ ║ 2 │ 4 │ 4 ║ ╚═════════╧═══════╧═══════╝
尝试了以下代码但未得到预期结果:
numberq=Question.objects.all().values('subject','topic').annotate(TotalQuestions=Count('topic')) numberq=Question.objects.all().values('subject','topic','id').order_by('subject','topic') numberq=df.groupby(['subject','topic'])['id'].count()#.size()
同时希望将结果中的subject_id和topic_id替换为对应的名称字段(Subject.subject和Topic.topic)。
解决方案
1. 基础分组统计(保留ID)
用Django ORM直接按科目、主题外键分组,统计问题ID的数量:
from django.db.models import Count # 统计每个科目-主题组的问题数量 question_counts = Question.objects.values('subject', 'topic').annotate( count=Count('id', distinct=True) ).order_by('subject', 'topic')
- 用
Count('id', distinct=True)确保每个问题只被计数一次,若确认无重复ID可省略distinct=True; values('subject', 'topic')指定分组依据,annotate添加统计字段;order_by保证结果按科目、主题排序。
2. 替换为名称字段
要显示科目和主题的名称,需关联查询对应模型的名称字段,在values中指定关联路径:
question_counts_with_names = Question.objects.values( 'subject__subject', # 对应Subject模型的subject名称字段 'topic__topic' # 对应Topic模型的topic名称字段 ).annotate( count=Count('id', distinct=True) ).order_by('subject__subject', 'topic__topic')
返回的结果会包含subject__subject(科目名称)、topic__topic(主题名称)和count三个键,直接对应名称显示需求。
3. 同时保留ID与名称
如果需要同时展示ID和名称,可在values中同时包含两类字段:
question_counts_full = Question.objects.values( 'subject', 'subject__subject', 'topic', 'topic__topic' ).annotate( count=Count('id', distinct=True) ).order_by('subject', 'topic')
4. 之前尝试的问题分析
- 第一个查询:
Count('topic')统计的是topic字段的非空次数,而非问题数量,应该统计id更准确; - 第二个查询:仅做了取值和排序,未执行聚合统计,因此没有数量字段;
- 第三个Pandas分组:若DataFrame数据正确,
df.groupby(['subject','topic'])['id'].count()是可行的,但直接用Django ORM统计更高效,无需额外导入数据到DataFrame。
内容的提问来源于stack exchange,提问作者Shiva
相关产品推荐
相关产品推荐

