如何在一次查询中从3张表取数?Django多表查询求助
解决班级详情页展示学生及统计数据的问题
嘿,我来帮你搞定这个展示班级学生和对应统计数据的问题!你之前用select_related没成功是因为用错了工具——select_related只适用于正向外键/一对一关系的关联查询,而你需要获取的是班级关联的学生(反向外键,对应related_name='students'),以及每个学生关联的统计数据(又是反向外键,related_name='statistics'),这时候得用prefetch_related,甚至结合Prefetch对象来实现嵌套预取,避免频繁查询数据库的N+1问题。
第一步:修改你的ClassesDetailView
你需要重写get_queryset方法,用嵌套的预取来一次性获取班级、学生和统计数据:
from django.db.models import Prefetch from django.views.generic.detail import DetailView from . import models class ClassesDetailView(DetailView): model = models.Classes context_object_name = "class_detail" template_name = "classesapp/class_detail.html" def get_queryset(self): # 预取当前班级的所有学生,同时预取每个学生的统计数据 return models.Classes.objects.prefetch_related( Prefetch( 'students', # 这里可以自定义学生的查询逻辑,比如按姓名排序 queryset=models.Students.objects.prefetch_related('statistics').order_by('name'), ) )
为什么这么写?
prefetch_related专门用来处理反向外键和多对多关系的批量预取,而select_related做不到这一点。- 嵌套使用
prefetch_related('statistics')在学生的查询集里,能确保每个学生的统计数据也被一次性拉取,不会在模板遍历的时候每次都发新的数据库查询。 Prefetch对象让你可以更灵活地控制预取的内容,比如给学生加排序、过滤条件,让展示更规整。
第二步:在模板里遍历数据
现在你可以在class_detail.html里轻松遍历班级的学生和对应的统计数据了:
<!-- classesapp/class_detail.html --> <h1>{{ class_detail.name }}</h1> <p>上课时间:{{ class_detail.day_and_time }}</p> <h2>班级学生列表</h2> {% for student in class_detail.students.all %} <div style="margin: 1rem 0; padding: 1rem; border: 1px solid #eee;"> <h3>{{ student.name }}</h3> <h4>统计记录</h4> {% if student.statistics.all %} <ul> {% for stat in student.statistics.all %} <li> <strong>日期:{{ stat.date }}</strong> | 听写:{{ stat.dictation_score }} | 写作:{{ stat.writing_score }} | 测试:{{ stat.test_score }} | 语法:{{ stat.grammar_score }} | 课堂表现:{{ stat.in_class_performance }} </li> {% endfor %} </ul> {% else %} <p>暂无统计数据</p> {% endif %} </div> {% empty %} <p>该班级还没有学生哦</p> {% endfor %}
额外小建议
按照Django的命名惯例,模型名建议用单数形式(比如Class代替Classes,Student代替Students),这样代码的可读性会更高,不过这不影响功能实现,只是风格上的优化~
内容的提问来源于stack exchange,提问作者Cheekou
相关产品推荐
相关产品推荐

