Как применить цикл 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
})
Вернуться на верх