
本文讲解如何使用 django 的 `filter()` 方法替代 `get()` 来安全查询多条数据库记录,并正确关联外键模型(如 student),避免“get() returned more than one”错误,同时提升视图逻辑的健壮性与可读性。
在 Django 开发中,Model.objects.get() 仅适用于预期且必须返回唯一一条记录的场景;一旦数据库中存在多条匹配数据,Django 将抛出 MultipleObjectsReturned 异常——这正是你遇到的 get() returned more than one ParentMystudent 错误的根本原因。
正确的做法是改用 Model.objects.filter(),它始终返回一个 QuerySet(即使为空或含多条),天然支持迭代、切片和链式查询,无需异常捕获即可安全处理零条、一条或多条结果。
以下是优化后的视图代码(含关键修正与最佳实践):
# views.py
from django.shortcuts import render
from django.db.models import Prefetch
def file_list_view(request):
# ✅ 使用 filter() 获取所有匹配的 ParentMystudent(注意:若 parent 字段是 ForeignKey,需确认是否应为 .parent_id)
parent_id = request.session.get('login_info', {}).get('id')
if not parent_id:
return render(request, 'file.html', {'query': []})
mystudents = ParentMystudent.objects.filter(parent=parent_id)
# ✅ 获取所有关联的 File 记录(使用 __in 支持多 mystudent_id)
mystudent_ids = mystudents.values_list('mystudent_id', flat=True)
files = File.objects.filter(studentid__in=mystudent_ids).select_related('studentid')
# ✅ 推荐:用 select_related 预加载外键(假设 File.studentid 是 ForeignKey(Student))
# 若 studentid 是外键字段名,则无需手动 get,模板中可直接访问 obj.studentid.lrn 等属性
# 此处假设字段名为 studentid → 对应 Student 模型实例
return render(request, 'file.html', {'query': files})⚠️ 注意事项:原代码中 File.objects.get(...) 和 Student.objects.get(...) 在循环内调用,会产生 N+1 查询问题,严重降低性能。应优先使用 select_related()(一对一/外键)或 prefetch_related()(多对多/反向关系)一次性预加载关联数据。mystudent.mystudent_id 是单个值,但 filter() 返回的是 QuerySet,不能直接取属性。因此需先提取 ID 列表(values_list('mystudent_id', flat=True)),再用 __in 进行批量匹配。模板中 obj.studentid.lrn 可直接使用(若已 select_related),无需手动赋值 obj.student = student;否则会覆盖原始字段且无法在模板中按预期渲染。
对应优化后的模板(file.html):
{% for obj in query %}
{{ forloop.counter }}
{{ obj.soano }}
{{ obj.studentid.lrn }}
{{ obj.studentid.lastname }}
查看文件
{% empty %}
暂无相关文件
{% endfor %}✅ 总结:
- 永远用 filter() 处理可能返回多条记录的查询;
- 用 select_related() 或 prefetch_related() 替代循环中多次 .get(),消除 N+1 查询;
- 善用 values_list(..., flat=True) 提取 ID 列表实现高效批量关联;
- 模板中尽量复用 ORM 预加载的关系,保持逻辑清晰、性能可控。










