Django множественный фильтр в одном столбце таблицы

я хочу получить тип запроса и отобразить количество для каждого продукта в этом типе

В views.py

def current(request):
    act=enquiry.objects.filter(type='Activity').values('product_name').distinct().annotate(Count('product_name'))
    wal=enquiry.objects.filter(type='Walkin').values('product_name').distinct().annotate(Count('product_name'))
    tele=enquiry.objects.filter(type='Tele').values('product_name').distinct().annotate(Count('product_name'))
    digital=enquiry.objects.filter(type='Digital').values('product_name').distinct().annotate(Count('product_name'))

В models.py

class product(models.Model):
    product_category=models.CharField(null=True,max_length=5000)
    product_category_id=models.CharField(null=True,max_length=5000)
    branch=models.CharField(default='',max_length=100)
    products=models.CharField(null=True,max_length=5000)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(default=timezone.now)
   
    def __str__(self):
     return '{},{}'.format(self.products, self.product_category)

class enquiry(models.Model):
    comment=models.CharField(default='',max_length=100,null=False)
    branch=models.CharField(default='',max_length=100)
    created_at = models.DateField(auto_now_add=True)
    updated_at = models.DateTimeField(default=timezone.now)
    created_by=models.CharField(default='',max_length=100)
    status=models.CharField(default='',max_length=100)
    commentupdate=models.CharField(default='',max_length=100)
    product=models.ForeignKey(product,models.CASCADE,default='')
    product_name=models.CharField(default='',max_length=100)
    product_category=models.CharField(default='',max_length=100)
    type=(
        ('Walkin','Walkin'),
        ('Activity','Activity'),
        ('TeleEnq','TeleEnq'),
        ('Digital','Digital'),
        )
    type=models.CharField(choices=type, default='',max_length=100)
    status_type=(
        ('Retail','Retail'),
        ('Closed','Closed'),
        )
    status_update=models.CharField(choices=status_type, default='open',max_length=100)

В html

  {%for pr in act%} 
  <tr>
  <td>{{forloop.counter}}</td>
  <td>{{pr.product_name}}</td>               
  <td>{{pr.product_name__count}}</td>
  {%endfor%}

  {%for pr in wal%}
  <td>{{pr.product_name__count}}</td>
  {%endfor%} 

  {%for pr in tele%}
  <td>{{pr.product_name__count}}</td>
  {%endfor%} 

  {%for pr in digital%}
  <td>{{pr.product_name__count}}</td>
  {%endfor%} 
  </tr>

Я хочу получить результат, подобный этому:

продукт walkin Активность Теле DIgital Всего
p1 4 1 3 0 8
p2 0 6 0 1 7
p3 2 1 3 0 6
p4 3 2 0 4 9
:------: :------: :-------: :----: :-------: :-----:
total 9 10 6 5 30

Во-первых, у меня есть несколько основных предложений по вашему стилю:

  1. Не используйте type в качестве поля/переменной, никогда. Вы можете назвать ее _type или type_ в примере. Использование имен встроенных функций - очень плохая практика.
  2. Не используйте одно и то же имя более одного раза для модели. Она может переопределить себя и повести себя неожиданно или выдать ошибку (type снова). Не говоря уже о том, что этот способ менее читабелен.
  3. Имена классов следует писать в CamelCase (enquiry - плохо, Enquiry - лучше).
  4. Если у вас есть ForeignKey в Enquiry в Product, не рекомендуется иметь также поля в Product, которые имеют одинаковое значение.

Советую вам изучить модель-отношения Django (ссылка внизу). Пока что я дам вам несколько советов, которые могут оказаться полезными.

models.py:

Enquiry(models.Model):
    ...
    product = product=models.ForeignKey(Product, related_name='enquires', on_delete=models.CASCADE, default='')
    ...

Тогда вы можете получить доступ к связанному объекту через:

an_enquiry = Enquiry.objects.get(id=1)
an_enquiry.product   # accesses the related object
an_enquiry.product.product_category   # returns the 'product_category' field value from related object

При необходимости можно легко изменить направление:

a_product = Product.objects.get(id=1)
all_queryset = a_product.enquires.all()   # returns all related objects in a QuerySet
wal_queryset = a_product.enquires.filter(a_type='Walkin')   # returns filtered QuerySet
wal_queryset.count()   # returns sum of objects in a queryset

А в вашем шаблоне:

{% for product in wal_queryset %}
    {{ product.wal_queryset.count }}
{% endfor %}

Прочитайте об этом в the Django docs, потому что это дает много возможностей. Понимание отношений делает Django очень мощным инструментом.

Используйте аннотацию и агрегацию

Я думаю, что, изучая документацию, вы будете использовать queryset

qs = Product.objects.all.annotate(
       walkin_count=Count('enquiry', filter=Q( enquiry__type='Walkin' ))
    ).annotate(
       activity_count=Count('enquiry', filter=Q( enquiry__type='Activity' ))
    ).annotate ...

Аннотация добавляет поля к извлекаемым объектам, поэтому в вашем шаблоне

{% for prod in products %}
    <tr>
      <td>{{prod}}</td>
      <td>{{prod.walkin_count}} </td>
      <td>{{prod.activity_count}} </td>
      ...
    </tr>

Последняя строка с итогами, я не уверен, что вы можете каким-то образом добавить их в тот же кверисет, но их легко вычислить из кверисета:

total_walkins = sum( [ prod.walkin_count for prod in qs ] )

и передайте их в контексте вашему шаблону.

BTW это соглашение Django/Python о том, что (модельные) классы начинаются с заглавной буквы. Это сбивает меня с толку, когда я пытаюсь интерпретировать product как модель, а не как экземпляр. В своем ответе я, вероятно, по привычке написал с заглавной буквы.

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