Рекурсивно считать все товары во всех подкатегориях - PullRequest
0 голосов
/ 28 сентября 2019

Я хочу перечислить все основные категории (чей родитель 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

Ответы [ 2 ]

0 голосов
/ 30 сентября 2019

Я добавил get_recursive_product_count метод для моей модели категории:

def get_recursive_product_count(self):
    return Product.objects.filter(category__in=self.get_descendants(include_self=True)).count()

... и использовал его в шаблоне так:

<ul>
  {% for child in category.get_children %}
    <li class='subcategory'><a href="/shop/category/{{ child.slug }}">{{ child.name }} ({{ child.get_recursive_product_count }})</a></li>
  {% endfor %}
</ul>         
0 голосов
/ 28 сентября 2019

Вы используете django-mptt, но не используете его в полной мере.Весь смысл алгоритма MPTT заключается в том, что вам не нужно повторять, вы можете вычислять такие вещи, как количество потомков за один раз.И это дает вам доступ к этому в одном методе: get_descendant_count.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...