Отношение фильтрации 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
со связанными Tasks
(в task_set
), отфильтрованными по тем, которые еще не завершены или завершены текущим пользователем.