You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 15:08:14