Как применить цикл for в Django views.py
[research/models.py]
RECRUITING_CHOICES = [
('Recruiting', 'Recruiting'),
('Not yet recruiting', 'Not yet recruiting'),
('Completed', 'Completed'),
('Holding', 'Holding'),
]
RECRUITING_CHOICES_INV = {val: val for val, _ in RECRUITING_CHOICES}
class Research(models.Model):
is_deleted = models.BooleanField(default=False)
is_recruiting = models.CharField(choices=RECRUITING_CHOICES, null=True, max_length=50)
research_name = models.CharField(max_length=2000, null=True)
teacher= models.CharField(max_length=2000, null=True)
Я использую Django, и я пытаюсь создать список для генерации apexchart (графика) в views.py, используя модель класса 'Research'.
Я пытаюсь добавить каждое из 4 значений поля is_recruiting в фильтрацию, но добавление Recruiting и Not yet Recruiting занимает несколько строк и делает код неэффективным. Есть ли обходной путь с использованием оператора for?
[research/views.py]
counts = Research.objects.values('teacher') \
.annotate(A=Count('id', filter=Q(type='A')),
B=Count('id', filter=Q(type='B')),
C=Count('id', filter=Q(type='C')),
D=Count('id', filter=Q(type='D')),
E=Count('id', filter=Q(type='E')),
F=Count('id', filter=Q(type='F')),
r_A=Count('id', filter=Q(type='A', is_recruiting='Recruiting')),
r_B=Count('id', filter=Q(type='B', is_recruiting='Recruiting')),
r_C=Count('id', filter=Q(type='C', is_recruiting='Recruiting')),
r_D=Count('id', filter=Q(type='D', is_recruiting='Recruiting')),
r_E=Count('id', filter=Q(type='E', is_recruiting='Recruiting')),
r_F=Count('id', filter=Q(type='F', is_recruiting='Recruiting')),
N_A=Count('id', filter=Q(type='A', is_recruiting='Not yet recruiting')),
N_B=Count('id', filter=Q(type='B', is_recruiting='Not yet recruiting')),
N_C=Count('id', filter=Q(type='C', is_recruiting='Not yet recruiting')),
N_D=Count('id', filter=Q(type='D', is_recruiting='Not yet recruiting')),
N_E=Count('id', filter=Q(type='E', is_recruiting='Not yet recruiting')),
N_F=Count('id', filter=Q(type='F', is_recruiting='Not yet recruiting'))) \
.values('teacher', 'A', 'B', 'C', 'D', 'E', 'F',
'r_A', 'r_B', 'r_C', 'r_D', 'r_E', 'r_F',
'N_A', 'N_B', 'N_C', 'N_D', 'N_E', 'N_F')
Вы можете наращивать динамические параметры ключевых слов в функции, создавая словарь параметров и распаковывая этот словарь при передаче с помощью **.
Переберите все типы и для каждого из них создайте ключи и значения для каждой аннотации, которую вы хотите использовать для этого типа.
Вы также можете распаковать созданные вами динамические аннотации в имена полей для передачи в values() с помощью *
annotations = {}
types = ('A', 'B', 'C', 'D', 'E', 'F')
for type in types:
annotations[type] = Count('id', filter=Q(type=type))
annotations[f'r_{type}'] = Count('id', filter=Q(type=type, is_recruiting='Recruiting'))
annotations[f'N_{type}'] = Count('id', filter=Q(type=type, is_recruiting='Not yet recruiting'))
counts = Research.objects.values('teacher').annotate(**annotations).values('teacher', *annotations.keys())
Kwargs могут быть переданы как dict, поэтому все, что вам нужно сделать, это создать dict с этими парами ключ: значение.
Вы можете сделать что-л. вроде:
recruiting_values = (
("", dict()),
("r_", dict(is_recruting="Recruiting")),
("n_", dict(is_recruting="Not"),
)
types = ("A", "B", "C")
...
.annotate(**{
f"{prefix}{type}": Count("id", filter=Q(type=type, **recruiting)) for prefix, recruiting in recruiting_value for type in types
})