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

如何在一次查询中从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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:04:34