I want to display subcategories title and its items under parent category in Django e.g. I have 1 parent category then it hast 2 sub cats and then each of them has 3 sub cats. in every sub category there are 10 items.
Parental category1
item1
item2
subcategory 1
item3
item4
item5
child category 1 from subcategory1
item6
item7
subcategory 2
item8
item9
item10
here is my codes:
Models.py
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
name = models.CharField(max_length=settings.BLOG_TITLE_MAX_LENGTH, unique=True)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
slug = models.SlugField(max_length=settings.BLOG_TITLE_MAX_LENGTH, null=True, blank=True)
description = models.TextField(null=True, blank=True)
class MPTTMeta:
order_insertion_by = ['name']
class Meta:
verbose_name_plural = 'Categories'
def __str__(self):
return self.name
def save(self, *args, **kwargs):
value = self.name
if not self.slug:
self.slug = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('items-by-category', args=[str(self.slug)])
class Item(models.Model):
title = models.CharField(max_length=settings.BLOG_TITLE_MAX_LENGTH)
category = TreeForeignKey('Category', on_delete=models.CASCADE, null=True, blank=True)
description = models.TextField(null=True, blank=True)
slug = models.SlugField(
max_length=settings.BLOG_TITLE_MAX_LENGTH,
)
def __str__(self):
return self.title
def get_absolute_url(self):
kwargs = {
'slug': self.slug
}
return reverse('item-detail', kwargs=kwargs)
def save(self, *args, **kwargs):
if not self.slug:
value = self.title
self.slug = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
Views.py
from django.views import generic
from .models import Item, Category
class CategoryListView(generic.ListView):
model = Category
template_name = "blog/category_list.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['items'] = Item.objects.all()
return context
class ItemsByCategoryView(generic.ListView):
ordering = 'id'
paginate_by = 10
template_name = 'blog/items_by_category.html'
def get_queryset(self):
# https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/#dynamic-filtering
# the following category will also be added to the context data
self.category = Category.objects.get(slug=self.kwargs['slug'])
queryset = Item.objects.filter(category=self.category)
# need to set ordering to get consistent pagination results
queryset = queryset.order_by(self.ordering)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['category'] = self.category
return context
class ItemDetailView(generic.DetailView):
model = Item
template_name = 'blog/item_detail.html'
items_by_category.html
{% extends "blog/base.html" %}
{% block title %}{{category.name}} list of items{% endblock %}
{% block content %}
<main>
<section>
<div class="container">
<h1>{{category}} items</h1>
<p>{{category.description}}.</p>
</div>
</section>
{% include "blog/_breadcrumbs.html" with ancestors=category.get_ancestors object=category%}
<div>
{% for item in object_list%}
<div>
<a href="{{item.get_absolute_url}}">
<p>{{item}}</p>
</a>
</div>
{% endfor %}
{% if is_paginated %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page=1">« first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last »</a>
{% endif %}
</span>
</div>
{% endif %}
</div>
</main>
{% endblock %}
thanks
I tried to display parental categories but it doesn't show anything