Home > Back-end >  Filter products using Category Model in Django
Filter products using Category Model in Django

Time:11-09

I'm building an ecommerce website and want to filter products using categories but I don't know how to render the products. And add the categories in the navigation bar from where people can navigate to different categories.

Here's my views.py file:

from django.shortcuts import render
from django.views import View
from .models import Product, Category

class ProductView(View):
    def get(self, request, *args, **kwargs):

        products = Product.objects.filter(is_active = True)


        context = {
            'products': products,
        }

        return render(request, 'Product/products.html', context)

class ProductDetailView(View):
    def get(self, request, slug):
        product = Product.objects.get(slug = slug)
        context = {
            'product': product
        }
        return render(request, 'Product/productdetail.html', context)

class CategoryView(View):
    def get(self, request):
        category = Category.objects.all()
        products = Product.objects.filter(category__slug = slug)

        context = {
            'category': category,
            'products':products,
         }
         return render(request, 'Product/category.html', context)

And this is my models.py

from django.db import models
from Seller.models import Seller

class Category(models.Model):
    category = models.CharField(max_length = 255)
    slug = models.SlugField(max_length = 255)

    def __str__(self):
        return self.category

class Product(models.Model):
    product = models.ForeignKey(Seller, on_delete = models.CASCADE)
    title = models.CharField(max_length = 255)
    image = models.ImageField(upload_to = 'images', null = True, blank = True)
    file = models.FileField(upload_to = 'files', null = True, blank = True)
    actual_price = models.PositiveIntegerField(default = '0')
    selling_price = models.PositiveIntegerField(default = '0')
    slug = models.SlugField(max_length = 255, unique = True)
    category = models.ForeignKey(Category, on_delete = models.CASCADE)
    description = models.TextField()
    is_active = models.BooleanField(default = True)

    def __str__(self):
        return self.title

I also don't know how to render it in html.

CodePudding user response:

To render you will need to use Django templates. They're not very hard to implement.

The template can start as something like this:

<html>
  <body>
    {% for product in products %}
      <a href="products/{{ product.id }}">
        <div>
          <img src="{{ product.image.url }}">
          <div>
            <h3> {{ product.title }}</h3>
            <p> {{ product.description|linebreaks }}</p>
          </div>
        </div>
      </a>
    {% endfor%}
  </body>
</html>

Filtering products based on category is simple:

products = Product.objects.filter(category__category='burger_buns')

If you want multiple categories:

category_names = 'burger_buns sausages hammers'.split()
products = Product.objects.filter(category__category__in=category_names)

Or you can use the reverse accessor (more here):

category = Category.objects.get(id=1)
products = category.product_set.all()

I highly recommend reading the docs on this.

CodePudding user response:

When you defined the ForeignKey relation to Category from Product, there'll also be a backward relationship. By default is named category.product_set. So in your template, when a user chooses a category instance, you can get its corresponding products with category1.product_set. To change this name, define a related_name for the ForeignKey relation.

category = models.ForeignKey(Category, related_name="products", on_delete = models.CASCADE)

now to access the category's corresponding products, just do something like category1.products.

CodePudding user response:

Your question is composed, then i'll answer to the categories issue (How to show categories in a nav bar and go through them).

views.py

from django.views.generic.list import ListView
from .models import Category, Product

class CategoryListView(ListView):
    model = Category
    # Override the context_object_name, default is 'object_list'
    context_object_name = 'categories'
    # Assume that category_list.html is in app/templates/ folder
    template_name = 'category_list.html'

class CategoryDetailView(DetailView):
    model = Category
    context_object_name = 'category'  # Default is 'object'
    # Assume that category_detail.html is in app/templates/ folder
    template_name = 'category_detail.html'
    
    # Add the product of this category to the context
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # This line retrieve all the products of this category
        context['products'] = self.product_set.all()
        return context

urls.py

from django.urls import path

from .views import CategoryListView, CategoryDetailView

urlpatterns = [
    path('category/', CategoryListView.as_view(), name='category-list'),
    path('category/<slug:slug>/', CategoryDetailView.as_view(), name='category-detail'),
]

category_list.html

<h1 class="head">Products Categories</h1>
{% for cat in categories %}
<div> 
    <a href="{% url 'category-detail' cat.slug %}">
        <h3>{{ cat.category }}</h3>
    </a>
</div>
{% endfor %}
</div>

category_detail.html

<h1 class="head">{{ category.category }}</h1>

<h3>Products for this category</h3>
<div>
    {% for product in products %}
    <div>
        <h5>{{ product.title }}<h5/>
        <div>{{ product.description }}</div>
        <img src="{{ product.image.url }}"/>
    </div>
    {% endfor %}
</div>

CodePudding user response:

first, you need to go to urls.py and do

urls.py as an example

from .view import CategoryView 
url_patterns =[
path("products/category/<slug:slug>/,CategoryView.as_view(),name="product-category")
]

in view

class CategoryView(View):
    def get(self, request, slug):
        category = Category.objects.all()
        products = Product.objects.filter(category__slug = slug)

        context = {
            'category': category,
            'products':products,
         }
         return render(request, 'Product/category.html', context)
  • Related