Я хочу перечислить все основные категории (чей родитель None
) и их прямые дочерние элементы (только подкатегории уровня 1).Я использую django-mptt
для моделирования своих категорий, и до сих пор мне удавалось рассчитывать только товары из одной прямой дочерней категории.
Мой взгляд такой:
def show_categories(request):
categories = Category.objects.filter(parent=None)
return render(request, 'products/categories.html', {'categories': categories})
и мой шаблон:
<div class='categories'>
<ul>
{% for category in categories %}
<li class='category'><a href="/shop/category/{{ category.slug }}">{{ category.name }}</a></li>
{% for child in category.get_children %}
<li class='subcategory'><a href="/shop/category/{{ child.slug }}">{{ child.name }} ({{ child.product_set.get_queryset.count }})</a></li>
{% endfor %}
{% endfor %}
</ul>
</div>
... так это работает так:
>>> from products.models import Product, Category
>>> c = Category(name='Books')
>>> c.save()
>>> c1 = Category(name='Textbooks', parent=c)
>>> c1.save()
>>> c2 = Category(name='Primary school', parent=c1)
>>> c2.save()
>>> p = Product(title='Math textbook', description='Math textbook for 4th grade', price=20, year=2018, category=c2)
>>> p.save()
>>> c.product_set.get_queryset().count()
0
... и я хочу, чтобы он вернул 1.
Мне нужно сосчитать все товары, которые относятся к категории «дочерние», и их потомков, поэтому могут быть книги -> Учебники -> Начальная школа, в настоящее времяЯ только получаю Учебники, и мне тоже нужно посещать Начальную школу.
Можно ли рекурсивно сосчитать все товары во всех подкатегориях?
@ РЕДАКТИРОВАТЬ:
Myмодели по запросу:
from django.db import models
from django.urls import reverse
from django.template.defaultfilters import slugify
from mptt.models import MPTTModel, TreeForeignKey
class Product(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=10)
year = models.PositiveSmallIntegerField()
image = models.ImageField(upload_to=get_image_path, blank=True, null=True)
date_added = models.DateTimeField(auto_now=True, null=True)
category = models.ForeignKey('Category', on_delete=models.CASCADE)
slug = models.SlugField()
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('products:product-detail', kwargs={'id': self.id, 'slug': self.slug})
class Category(MPTTModel):
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
name = models.CharField(max_length=255)
slug = models.SlugField()
class Meta:
unique_together = (('parent', 'slug',))
verbose_name_plural = 'categories'
class MPTTMeta:
order_insertion_by = ['name']
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super().save(*args, **kwargs)
def get_slug_list(self):
ancestors = self.get_ancestors(include_self=True)
slugs = [ancestor.slug for ancestor in ancestors]
new_slugs = []
for idx, ancestor in enumerate(slugs, 1):
new_slugs.append('/'.join(slugs[:idx]))
return new_slugs