如何在 Django 中通过条件筛选获取数据库中的多列数据

8次阅读

如何在 Django 中通过条件筛选获取数据库中的多列数据

本文讲解如何使用 django 的 `Filter()` 方法安全地查询多个匹配记录,替代可能引发“multipleobjectsreturned”异常的 `get()`,并正确关联外键数据、渲染模板。

django 开发中,Model.objects.get() 仅适用于严格预期且保证唯一的查询场景;一旦数据库中存在多条匹配记录,Django 将抛出 MultipleObjectsReturned 异常(如错误提示 “get() returned more than one ParentMystudent — it returned 2!”),导致请求中断。而本例中,一个家长(ParentMystudent)可能关联多个学生文件(File),因此必须改用 filter() —— 它返回 QuerySet(惰性可迭代对象),天然支持多结果处理。

以下是修正后的推荐写法(含性能与健壮性优化):

# views.py def file_list_view(request):     parent_id = request.session.get('login_info', {}).get('id')     if not parent_id:         return render(request, 'file.html', {'query': []})      # ✅ 使用 filter 获取所有关联的 ParentMystudent(即使多个也安全)     mystudents = ParentMystudent.objects.filter(parent=parent_id)     mystudent_ids = mystudents.values_list('mystudent_id', flat=True)      # ✅ 基于 ID 列表批量查询 File(避免 N+1 查询)     files = File.objects.filter(studentid__in=mystudent_ids).select_related('studentid')      # ✅ 预加载 Student 关联(假设 File.studentid 是外键指向 Student.registerid)     # 注意:若 File.studentid 字段实际关联的是 Student.registerid,则需确保模型定义了 proper ForeignKey 或使用 prefetch_related + custom annotation     # 更稳妥方式(推荐):     files = File.objects.filter(         studentid__in=mystudent_ids     ).select_related(         'studentid'  # 假设 File.studentid 是 ForeignKey(Student, to_field='registerid')     )      return render(request, 'file.html', {'query': files})

关键改进说明:

  • ❌ 避免 get() 用于多结果场景;✅ 统一使用 filter() 并检查 QuerySet 是否为空(if query 可直接判断,但更推荐 if query.exists() 提升效率)。
  • ❌ 禁止在循环内执行 Student.objects.get()(N+1 查询);✅ 使用 select_related() 预关联外键,一次 sql 加载全部所需数据。
  • ✅ 添加空值防护(如 request.session.get(…)),防止 KeyError。
  • ✅ 使用 values_list(‘field’, flat=True) 提取 ID 列表,适配 __in 查询,语义清晰且高效。

模板(file.html)同步更新(无需修改逻辑,但更简洁):

{% for obj in query %}      {{ forloop.counter }}     {{ obj.soano }}     {{ obj.studentid.lrn }}       {{ obj.studentid.lastname }}  {% empty %} 暂无文件记录 {% endfor %}

⚠️ 注意事项:

  • 确保 File.studentid 字段确为 ForeignKey(Student, to_field=’registerid’) 类型;否则需用 prefetch_related() 或原生 SQL 关联。
  • 若 ParentMystudent.mystudent_id 并非外键字段而是普通整型字段,请确认其值与 Student.registerid 一致,否则关联将失效。
  • 生产环境建议添加日志或监控,捕获意外的空 mystudents 或 files,便于排查权限或数据一致性问题。

掌握 filter() 与 select_related()/prefetch_related() 的组合使用,是构建高性能、高可靠 Django 查询的基础能力。

text=ZqhQzanResources