ListView中的Django过滤关系

Posted

技术标签:

【中文标题】ListView中的Django过滤关系【英文标题】:Django filtering relation in ListView 【发布时间】:2022-01-03 09:41:52 【问题描述】:

给定模型

class TaskGroup(models.Model):
    name = models.CharField(max_length=256)

class Task(models.Model):
    name = models.CharField(max_length=256)
    group = models.ForeignKey(TaskGroup, on_delete=models.CASCADE)
    completed = models.BooleanField(default=False)
    completed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)

和列表视图

class TaskGroupListView(ListView):
   model = TaskGroup

我想显示具有相应任务的任务组列表。问题是 - 我只想显示尚未完成或已由用户完成的任务,或者如果用户作为属性 user.type == "ADMIN" 设置显示所有组和所有任务。

现在我有一个看起来像这样的模板:

% for taskgroup in object_list %
<h1> taskgroup.name </h1>
<ul>
    % for task in taskgroup.task_set.all %
    <li> task.name </li>
    % endfor %
</ul>
% endfor %

我知道我可以通过覆盖get_queryset 来修改列表视图的查询集,例如:

def get_queryset(self):
    if self.request.user == "ADMIN":
        return TaskGroup.objects.all()
    else:
        ...

但我不确定如何过滤 else 子句中 TaskGroups 上的 Task 关系。

我考虑过为 Task 创建一个管理器子类,它可以根据我可以在模板中使用的 .completed.completed_by 进行过滤,但这似乎违背了 Django 的理念 - 我想保留视图中的所有逻辑(这可能有点离题,所以请纠正我,自从我接触 django/读过两勺 django 已经有一段时间了)。

有没有一些惯用的方法来做到这一点?我应该完全放弃 ListView 并编写一些自定义逻辑吗?这里的任何指导都是有帮助的。谢谢。

【问题讨论】:

【参考方案1】:

您可以将prefetch_related 与使用自定义过滤查询集的Prefetch 一起使用,如下所示:

from django.db.models import Prefetch, Q


def get_queryset(self):
    if self.request.user.is_admin:
        return TaskGroup.objects.all()

    return TaskGroup.objects.prefetch_related(
        Prefetch(
            'task_set',
            queryset=Task.objects.filter(Q(completed=False) | Q(completed_by=self.request.user))
        )
    )

这将获得所有TaskGroups 以及相关Taskss(在task_set 中),这些@s

【讨论】:

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

无法将 extra_context 添加到 ListView

Django REST Framework 中的否定或排除过滤器

django 过滤特定用户组中的客户

将参数传递给 Django 中的 ListView

Django ListView - 过滤和排序的表单

Django:将过滤(和排序)添加到基于(通用)类的ListView的最佳方法?