Отношение фильтрации Django в ListView

С учетом моделей

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:
        ...

но я не уверен, как отфильтровать отношения Task на TaskGroup в предложении else.

Я думал о создании подкласса менеджера для Task, который может фильтровать на основе .completed и .completed_by, который я могу использовать в шаблоне, но это кажется противоречащим философии Django - я хотел бы сохранить всю логику в представлении (это может быть не совсем верно, поэтому, пожалуйста, поправьте меня, я давно не прикасался к django/прочитал две ложки django).

Есть ли какой-то идиоматический способ сделать это? Должен ли я полностью отказаться от ListView и написать какую-то собственную логику? Любое руководство здесь будет полезно. Спасибо.

Вы можете использовать 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))
        )
    )

Это позволит получить все TaskGroup со связанными Taskstask_set), отфильтрованными по тем, которые еще не завершены или завершены текущим пользователем.

Вернуться на верх