Home > Software design >  find top performing list of category which have highest number of orders in django
find top performing list of category which have highest number of orders in django

Time:04-23

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.

  • Related