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 |
Во-первых, у меня есть несколько основных предложений по вашему стилю:
- Не используйте
typeв качестве поля/переменной, никогда. Вы можете назвать ее_typeилиtype_в примере. Использование имен встроенных функций - очень плохая практика. - Не используйте одно и то же имя более одного раза для модели. Она может переопределить себя и повести себя неожиданно или выдать ошибку (
typeснова). Не говоря уже о том, что этот способ менее читабелен. - Имена классов следует писать в CamelCase (
enquiry- плохо,Enquiry- лучше). - Если у вас есть
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 как модель, а не как экземпляр. В своем ответе я, вероятно, по привычке написал с заглавной буквы.