models.py
class Line_items(models.Model):
id = models.AutoField(primary_key=True)
product = models.ForeignKey('Products' , on_delete=models.DO_NOTHING )
class Products(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=400 , blank=True)
category = models.ManyToManyField('Categories', through='Product_Categories', related_name='products')
class Categories(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100 , blank=True)
slug = models.CharField(max_length=200 , blank=True)
class Product_Categories(models.Model):
id = models.AutoField(primary_key=True)
product_id = models.ForeignKey(Products, on_delete=models.DO_NOTHING)
category_id = models.ForeignKey(Categories, on_delete=models.DO_NOTHING)
here are my models. where line_items contains number of orders done till now. in line_items we have connect product id with product table. but we don't have any connetion from product table to category table. ( category table contains every category and their id ).
to connect product table with category table we have created new table 'product_categories' which connects each category with their respective product.
here what we want is top performing category. category which have highest number of orders. thanks
CodePudding user response:
The class Product_Categories has no sense. You can delete it. One advice, call your models in plural is a bad practice. It would be better "Category", "Product", ...
If you want to know how many products are in a category, just do this:
# ON VIEWS
category = Categories.objects.first() #The category you want to check
category.products.count() #Number of products included in this category
If you want to show a list with categories and products included in your template:
#ON VIEWS
context = {}
context['categories'] = Categories.objects.all()
#ON TEMPLATE
<ul>
{% for c in categories %}
<li>{{c.name}} - {{c.products.count}}</li>
{% endfor %}
</ul>
If you want the top one. The category with more products:
from django.db.models import Count
top_category = Categories.objects.annotate(q_count=Count('products')).order_by('-q_count').first()
EDIT:
I don't find an "easy way" to get the category with more orders. But you can try this:
from operator import itemgetter
categories = Categories.objects.all()
category_orders = []
for c in categories:
x=0
for p in c.products.all():
x = p.line_items_set.count()
category_orders.append(c,x)
top_category = max(list,key=itemgetter(1))[0]
CodePudding user response:
You can span relationship when using the Count
-method in django.db.models
.
cats = Category.objects.annotate(num=Count("products__line_items")).order_by("-num")
The resulting queryset will return you the categories which have the most line_items.
You can of course limit them to only show categories that have any orders:
line_items_ids = [li.id for li in Line_items.objects.all()]
cats = (
Category.objects.filter(products__line_items__in=line_items_ids)
.annotate(num=Count("products__line_items"))
.order_by("-num")
)
Have a look at Django Docs about aggregation for more documentation.