Home > other >  How to apply for loop in Django's views.py
How to apply for loop in Django's views.py

Time:02-15

[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)

I'm using Django, and I'm trying to create a list for generating apexchart (graph) in views.py using a class model 'Research'.

I am trying to add each of the 4 values ​​of the is_recruiting field to filtering , but adding Recruiting and Not yet Recruiting just takes multiple lines and makes the code look inefficient. Is there a workaround using the for statement?

[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')

----------------------ADD--------------------------- [views.py - ADD]

teacher = [];
A= [];
B= [];
C= [];
D= [];
E= [];
F= [];
r_A = [];
r_B = [];
r_C = [];
r_D = [];
r_E = [];
r_F = [];
for count in counts:
    teacher.append(str(count['teacher']))
    A.append(str(count['A']))
    B.append(str(count['B']))
    C.append(str(count['C']))
    D.append(str(count['D']))
    E.append(str(count['E']))
    Ftc.append(str(count['F']))
    r_A.append(str(count['r_A']))
    r_B.append(str(count['r_B']))
    r_C.append(str(count['r_C']))
    r_D.append(str(count['r_D']))
    r_E.append(str(count['r_E']))
    r_F.append(str(count['r_F']))

is_recruiting = request.GET.get('is_recruiting')

[graph.html]

<script>
    var options3 = {
    series: [{% if is_recruiting == 'Recruiting' %}
    {
      name: 'A',
      data: {{ r_A | safe }}
    }, {
      name: 'B',
      data: {{ r_B | safe }}
    }, {
      name: 'C',
      data: {{ r_C | safe }}
    }, {
      name: 'D',
      data: {{ r_D | safe }}
    }, {
      name: 'E',
      data: {{ r_E | safe }}
    }, {
      name: 'F',
      data: {{ r_F | safe }}
    },{% elif is_recruiting == 'ALL' %}
    {
      name: 'A',
      data: {{ A | safe }}
    }, {
      name: 'B',
      data: {{ B | safe }}
    }, {
      name: 'C',
      data: {{ C | safe }}
    }, {
      name: 'D',
      data: {{ D | safe }}
    }, {
      name: 'E',
      data: {{ E | safe }}
    }, {
      name: 'F',
      data: {{ F | safe }}
    },{% endif %}
    ],
</script>

Do I have to list the if statements over and over in the JavaScript part?

CodePudding user response:

You can build up dynamic keyword parameters to a function by creating a dictionary of the parameters and unpacking that dictionary as you pass it with **.

Loop over your types and for each one create keys and values for each annotation that you want for that type.

You can also unpack the dynamic annotations you created into field names to pass to values() using *

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())

CodePudding user response:

Kwargs can be passed as dict, so all you need to do is to create a dict with these key: value pairs.

You could do sth like:

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
})
  • Related