milan
milan

Reputation: 2417

show count and top_categories in the homepage

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

Answers (3)

Astik Anand
Astik Anand

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

binpy
binpy

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

Bestasttung
Bestasttung

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

Some doc to override managers

Upvotes: 0

Related Questions