Django多外键关联过滤:教师页面按分类去重展示评论学生
解决同一分类下重复显示评论学生的问题
我来帮你搞定这个重复显示的问题!核心思路就是针对每个分类,获取所有评论过该分类下博客的学生,并对学生进行去重。下面分步骤给你具体实现方案:
1. 先补全必要的模型关联(如果还没定义的话)
首先得确保你的博客(Blog)和评论(Comment)模型正确关联到分类和学生:
from django.db import models from django.contrib.auth.models import User class Genre(models.Model): name = models.CharField(max_length=200, unique=True) class Student(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) # 其他学生相关字段,比如学号、班级等 class Blog(models.Model): genre = models.ForeignKey(Genre, on_delete=models.CASCADE, related_name='blogs') title = models.CharField(max_length=200) # 其他博客字段,比如内容、发布时间等 class Comment(models.Model): student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='comments') blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name='comments') content = models.TextField() created_at = models.DateTimeField(auto_now_add=True)
2. 方法一:在Genre模型中添加去重查询方法
直接在分类模型里定义一个方法,用来获取该分类下所有评论过博客的唯一学生:
class Genre(models.Model): name = models.CharField(max_length=200, unique=True) def get_unique_comment_students(self): # 通过评论->博客->分类的关联,筛选出所有评论过该分类博客的学生,并去重 return Student.objects.filter(comments__blog__genre=self).distinct()
这里的distinct()会帮我们自动去掉重复的学生对象,因为同一个学生可能评论多篇同分类博客,filter会返回多条重复的学生记录,distinct()会根据学生的主键去重。
3. 方法二:视图层预取去重数据(性能更优)
如果你的分类和学生数据量比较大,推荐在视图里用Prefetch预取去重后的学生,减少数据库查询次数:
from django.db.models import Prefetch from django.shortcuts import render from .models import Genre, Student def teacher_profile(request): # 预取每个分类下的唯一评论学生 unique_students_prefetch = Prefetch( 'blogs__comments__student', queryset=Student.objects.distinct(), to_attr='unique_students' ) # 获取所有分类并预取数据 genres = Genre.objects.prefetch_related(unique_students_prefetch).all() return render(request, 'teacher_profile.html', {'genres': genres})
4. 模板层渲染展示
不管用哪种方法,模板里都可以这样遍历展示:
{% for genre in genres %} <h2>{{ genre.name }}</h2> {% if genre.get_unique_comment_students %} {# 方法一用这个判断 #} {% if genre.unique_students %} {# 方法二用这个判断 #} <ul> {% for student in genre.get_unique_comment_students %} {# 对应方法一 #} {% for student in genre.unique_students %} {# 对应方法二 #} <li>{{ student.user.username }}</li> {% endfor %} </ul> {% else %} <p>暂无学生对该分类博客发表评论</p> {% endif %} {% endfor %}
额外说明
distinct()的作用:它会告诉数据库返回唯一的记录,Django会根据模型的主键来判断唯一性,所以同一个学生只会被返回一次。- 性能优化:如果用方法二的
Prefetch,Django只会执行两次数据库查询(一次获取所有分类,一次获取所有关联的去重学生),比方法一中每个分类单独查询学生要高效得多,适合数据量大的场景。
内容的提问来源于stack exchange,提问作者tei1
相关产品推荐
相关产品推荐

