Reputation: 2417
I want to show top_categories in the homepage. I have written top_categories function to list the categories that has most number of products. But I have written this function in Product Model. I am confused on where should I write this. Here is my code
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
class Product(models.Model):
name = models.CharField(max_length=200, unique=True,
blank=False, null=False)
categories = models.ManyToManyField(Category, related_name='products')
def top_categories(self):
product = Product.objects.values('id').annotate(
categories_count=models.Count('categories')).order_by('-categories_count')
return product
def home(request):
categories = Category.objects.all()
companies = Company.objects.all()[:12]
context = {
'categories': categories,
'companies': companies
}
return render(request, 'company/home.html', context)
Now there is a confusion, Do I have to implement top_categories function in Category modal or the way I am doing is fine? Because the job of showing the content in homepage is the role of home view.
Upvotes: 2
Views: 52
Reputation: 13047
You can do it in views.py
def home(request):
# arrange your category on basis of product_count
categories = Category.objects.annotate(product_count = Count('products')).order_by('-product_count')
# if you want only top 10 categories
# categories = categories[:10]
companies = Company.objects.all()[:12]
context = {
'categories': categories,
'companies': companies
}
return render(request, 'company/home.html', context)
In home.html
{% for category in categories %}
<h3> category name:</h3>{{category.name}}
<h3> Total product::</h3>{{category.product_count}}
{% endfor %}
Upvotes: 1
Reputation: 4194
I suggest you to using templatetags, because if you handle this case with views
you will create similiar popular filter for another page.
# yourapp/templatetags/popcategories.py
from django import template
from yourapp.models import (Category, Product)
register = template.Library()
@register.assignment_tag
def popular_categories():
categories = Category.objects.all()
get_total = lambda c: Product.objects.filter(categories__slug=c.slug).count()
tags_list = [{'category': category, 'total': get_total(category)} for category in categories]
tags_list.sort(key=lambda x: int(x['total']), reverse=True)
return tags_list[:10] # return 10 top
And then, you can use it in your template company/home.html
with;
{% load popcategories %}
{% popular_categories as categories_list %}
{% for category in categories_list %}
<a href="">
{{ category.name }} - {{ category.slug }}
</a>
{% empty %}
<p>No categories yet!</p>
{% endfor %}
Upvotes: 0
Reputation: 2458
Well think I would do something like this :
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
@staticmethod
def top_category():
return models.Count('categories')).order_by('-categories_count')
Made it a static method cause it's not about an instance. An even better way of doing it would be to extends the Category manager and add a method get_top_category
to it so you can call a Category.objects.get_top_category()
. Then just call it in your Product model :
def top_products(self):
count_category = Category.top_category() # or Category.objects.get_top_category() if you have done it this way
product = Product.objects.values('id').annotate(count_category)
return product
Upvotes: 0