Django过滤多个外键关系

Posted

技术标签:

【中文标题】Django过滤多个外键关系【英文标题】:Django filter multiple foreign key relationships 【发布时间】:2018-08-28 18:05:14 【问题描述】:

我想列出对每种类型的博客文章发表评论的老师的所有学生。以下是我的最大努力,但我为每个类型重复了学生的名字,所以如果他们评论多篇可怕的博客文章,他们的名字会被多次列出。如何在教师资料页面上的每个流派旁边列出每个学生的姓名?

Models.py

class Genre(models.Model):
    name = models.CharField(max_length=200, unique=True)

class Student(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='student_profile')
    username = models.CharField(max_length=128, unique=True)
    teacher = models.ForeignKey('Teacher', blank=True, null=True)

class Teacher(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='teacher_profile')
    name = models.CharField(max_length=128, blank=True, unique=True)

class BlogPost(models.Model):
    genre = models.ForeignKey(Genre, on_delete=models.CASCADE, null=True)

class Comment(models.Model):
    blogpost = models.ForeignKey(BlogPost, related_name='comments', on_delete = models.CASCADE, null=True)
    message = CharField(max_length=1000, blank=True)
    commenter = models.ForeignKey(User, related_name='comments', on_delete=models.CASCADE, null=True)

Views.py

def teacher_profile(request):
student_list = Student.objects.filter(teacher__user=request.user)
student_blogpost_list = BlogPost.objects.filter(comments__commenter__student_profile__teacher__user=request.user).distinct()
student_genre_list = Genre.objects.filter(blogpost__in=student_blogpost_list).distinct()
return render(
    request,
    'myapp/teacher_profile.html',
    context= 'student_list':student_list, 'student_blogpost_list':student_blogpost_list, 'student_genre_list':student_genre_list,
)

teacher_profile.html

% if student_genre_list %
  <h4>Genres</h4>
  % for genre in student_genre_list %
    Genre:  genre.name  - Students: 
    % for blogpost in genre.blogpost_set.all %
      % for comment in blogpost.comments.all %
        % if comment.commenter.student_profile in student_list %
           comment.commenter.student_profile.username 
        % endif %
      % endfor %
    % endfor %
  <br>
  % endfor %
% endif %

【问题讨论】:

【参考方案1】:

我想可以通过以下方式完成:

student_list = Student.objects.filter(teacher__user=request.user)
student_blogpost_list = BlogPost.objects.filter(comments__commenter__student_profile__teacher__user=request.user).distinct()

data = dict()
for blogpost in student_blogpost_list:
    students_usernames = list(blogpost.comment_set.filter(commenter__in=student_list).
                             values_list('commenter__student_profile__username', flat=True))
    if blogpost.genre.name in data:
        data[blogpost.genre.name].append(students_usernames)
    else:
        data[blogpost.genre.name] = students_usernames

for key in data.keys():
    data[key] = set(data[key]) # remove duplicates from list

data 变量将等于:

'genre_1': 'username_1', 'username_2', 'genre_2': 'username_2', 'username_3', 'username_4'

我的意思是模板中不应该有很多逻辑。使用这种方法,您只需要遍历结果字典。 不过,我不能保证这段代码可以正常工作,因为我没有使用相同的方案设置数据库。

【讨论】:

以上是关于Django过滤多个外键关系的主要内容,如果未能解决你的问题,请参考以下文章

Django admin 查询集通过外键向后关系过滤

Django过滤器遍历多个外键和通用外键

Django:遍历模板中的过滤列表

如何通过Django中的prefetch_related过滤具有多个条件的反向外键

Django自递归外键过滤器查询所有孩子

带有嵌套序列化程序的 Django 反向外键给出了多个结果