Linux Kyrios
Linux Kyrios

Reputation: 1

Django - how to create proper categories and subcategories

I am currently working on a store made in Django and I have a problem because I have a model for Category as well as Subcategory. The problem is that I don't really know what I did wrong, because in the html file I try to call both categories and subcategories, but in each category all subcategories are displayed, instead of belonging to a specific category. I would like to ask for your help, and check, if files below are correctly written. Thanks in advance

models.py

from django.db import models
from django.urls import reverse


# Class model for category
class Category(models.Model):
    name = models.CharField(max_length=200,
                            db_index=True)
    slug = models.SlugField(max_length=200,
                            db_index=True)

    class Meta:
        ordering = ('name',)
        verbose_name = 'category'
        verbose_name_plural = 'categories'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('selcorshop:product_list_by_category',
                       args=[self.slug])


# Class model for subcategory
class Subcategory(models.Model):
    category = models.ForeignKey(Category,
                                 related_name='category',
                                 on_delete=models.CASCADE)
    name = models.CharField(max_length=200,
                            db_index=True)
    slug = models.SlugField(max_length=200,
                            db_index=True)

    class Meta:
        ordering = ('name',)
        verbose_name = 'subcategory'
        verbose_name_plural = 'subcategories'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('selcorshop:product_list_by_subcategory',
                       args=[self.slug])


# Class model for product
class Product(models.Model):
    subcategory = models.ForeignKey(Subcategory,
                                 related_name='products',
                                 on_delete=models.CASCADE)
    name = models.CharField(max_length=200, db_index=True)
    slug = models.SlugField(max_length=200, db_index=True)
    image = models.ImageField(upload_to='products/%Y/%m/%d',
                              blank=True)
    description = models.TextField(blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    available = models.BooleanField(default=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ('name',)
        index_together = (('id', 'slug'),)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('selcorshop:product_detail',
                       args=[self.id, self.slug])

views.py

from django.shortcuts import render, get_object_or_404
from .models import Category, Subcategory, Product
from cart.forms import CartAddProductForm


# View for product list in site
def product_list(request, category_slug=None, subcategory_slug=None):
    category = None
    categories = Category.objects.all()
    subcategory = None
    subcategories = Subcategory.objects.all()
    products = Product.objects.filter(available=True)
    if category_slug:
        category = get_object_or_404(Category, slug=category_slug)
        subcategory = get_object_or_404(Subcategory, slug=subcategory_slug)
        products = products.filter(category=category)
    return render(request,
                  'selcorshop/product/list.html',
                  {'category': category,
                   'categories': categories,
                   'subcategory': subcategory,
                   'subcategories': subcategories,
                   'products': products})


# View for single product
def product_detail(request, id, slug):
    product = get_object_or_404(Product,
                                id = id,
                                slug = slug,
                                available = True)
    # Add to cart button
    cart_product_form = CartAddProductForm()
    return render(request,
                  'selcorshop/product/detail.html',
                  {'product': product,
                   'cart_product_form': cart_product_form})

urls.py

from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static


app_name = 'selcorshop'
urlpatterns =[
    path('', views.product_list, name='product_list'),
    path('<slug:category_slug>/', views.product_list, name='product_list_by_category'),
    path('<slug:subcategory_slug>/', views.product_list, name='product_list_by_subcategory'),
    path('<int:id>/<slug:slug>/', views.product_detail, name='product_detail'),
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

list.html

{% extends "selcorshop/base.html" %}
{% load static %}

{% block title %}
    {% if category %}{{ category.name }}{% else %}Produkty{% endif %}
{% endblock %}

{% block content %}

<div class="row">
<div id="sidebar" class="col-2">
    <div class="d-flex flex-column flex-shrink-0 p-3 text-white bg-dark" style="width: 280px;">
    <a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none">
        <svg xmlns="http://www.w3.org/2000/svg" width="40" height="32" fill="currentColor" class="bi bi-list" viewBox="0 0 16 16">
            <path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"/>
        </svg>
      <span class="fs-4">Kategorie</span>
    </a>
    <hr>
        <ul class="nav nav-pills flex-column mb-auto">
            <li {% if not category %}class="nav-item" {% endif %}>
                <a href="{% url 'selcorshop:product_list' %}" class="nav-link active bg-success" aria-current="page">Wszystkie</a>
            </li>
            <div class="dropdown">
            **{% for c in categories %}
            <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                <li {% if category.slug == c.slug %} {% endif %}>
                    <a href="{{ c.get_absolute_url }}" class="nav-link text-white">{{ c.name }}</a>
                </li>
            </button>
                <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
                    {% for s in subcategories %}
                    <a class="dropdown-item" href="#">
                        <li {% if subcategory.slug == s.slug %} {% endif %}>
                            <a href="{{ s.get_absolute_url }}" class="nav-link text-black">{{ s.name }}</a>
                        </li>
                    </a>
                    {% endfor %}
                </div>
            {% endfor %}**
            </div>
        </ul>
<!--    <ul class="nav nav-pills flex-column mb-auto">-->
<!--      <li {% if not category %}class="nav-item" {% endif %}>-->
<!--        <a href="{% url 'selcorshop:product_list' %}" class="nav-link active" aria-current="page">Wszystkie</a>-->
<!--      </li>-->
<!--      {% for c in categories %}-->
<!--      <li {% if category.slug == c.slug %} {% endif %}>-->
<!--        <a href="{{ c.get_absolute_url }}" class="nav-link text-white">{{ c.name }}</a>-->
<!--      </li>-->
<!--      {% endfor %}-->
<!--      </ul>-->
    </div>
</div>

<div id="main" class="product_list col-10">
    <h2>{% if category %}{{ category.name }}{% else %}Produkty{% endif %}</h2>
    {% for product in products %}
        <div class="item">
            <a href="{{ product.get_absolute_url }}">
                <img src="{% if product.image %}{{ product.image.url }}{% else %}{% static 'img/no_image.png' %}{% endif %}" alt="Obraz">
            </a>
            <a href="{{ product.get_absolute_url }}">{{ product.name }}</a><br>
            {{ product.price }} zł.
        </div>
    {% endfor %}
</div>



</div>

{% endblock %}

Upvotes: 0

Views: 1044

Answers (1)

Shreyash mishra
Shreyash mishra

Reputation: 790

So after seeing your code I guess you want to create a dropdown menu in which all the subcategory list related to category open right so for that you can call it with related name which you pass in your subcategory model a use it in your HTML like that

{% for c in category_list  %}
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle text-dark" href="#" id="navbarDarkDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false" style="font-weight:500">
              <strong>{{ c.name }}</strong>
            </a>
            <ul class="dropdown-menu" aria-labelledby="navbarDarkDropdownMenuLink">
              {% for subcategory in c.category.all %}
              <li><a class="dropdown-item" href="#">{{ subcategory.name }}</a>
              {% endfor %}
            </ul>
          </li>
          {% endfor %}

this has to solve your problem andd tell me if you still got any issue

Upvotes: 1

Related Questions