Как в django вывести в шаблон count всех объектов подподкатегории?

Уважаемые знатоки! Помогите решить проблему. Структура моделей такова:
Категория -> подкатегория -> подподкатегория -> объявление. Все через ForeignKey. Задача вывести количество объявлений в скобках в списке Категорий. В списке подкатегорий вывожу очень просто
{%for category in subcategory_list%}
      <li>{{category.title}}<span>{{category.subsubcategory.order_set.count}}</span></li>
 {%endfor%}

А вот с Категориями сложнее по моей логике пытался сделать так):
{%for subcategory in category.subcategory_set.all%}
      <li>{{subcategory.title}}<span>{{subcategory.subsubcategory_set.all.order_set.count}}</span></li>
{%endfor%}

Естественно не вышло)
  • Вопрос задан
  • 2843 просмотра
Пригласить эксперта
Ответы на вопрос 2
sergey-gornostaev
@sergey-gornostaev Куратор тега Django
Седой и строгий
Прежде всего, если используете иерархические структуры данных, то используйте их с django-mptt. Во-первых, это позволит работать с любым уровнем вложенности, в том числе неопределённым на этапе разработки и переменным в разных ветках. Во-вторых, это облегчит вам работу, предоставив простые и эффективные методы манипуляции ветками. Наконец, это позволит получать данные из БД наиболее быстрым и эффективным способом, с минимальной затратой ресурсов.

Конкретно по вашей задаче решением в лоб было бы определить в модели свойство, возвращающее количество объявлений в дочерних категориях:
class Category(models.Model):
    parent = TreeForeignKey('self', verbose_name=u'Родитель', null=True, blank=True, related_name='children')
    title = models.CharField(u'Название', max_length=100)

    @property
    def items_count(self):
        # получаем список идентификторов всех низлежащих категорий, включая интересующую нас
        ids = self.get_descendants(include_self=True).values_list('id')
        # возвращаем количество товаров, имеющих родителем категорию с идентификатором входящим
        # в список полученный строкой выше
        return Product.objects.filter(parent_id__in=ids).count()

и потом вывести их в шаблоне как-то так
<ul class="root">
    {% recursetree nodes %}
        <li>
            {{ node.title }}<span>{{ note.items_count }}</span>
            {% if not node.is_leaf_node %}
                <ul class="children">
                    {{ children }}
                </ul>
            {% endif %}
        </li>
    {% endrecursetree %}
</ul>

Но беда в том, что это квадратичный алгоритм, чем больше будет категорий отображаться на странице, тем больше запросов будет к базе при открытии этой страницы. Я так и не нашёл в Django лучшего решения для этого, чем делать сырой SQL запрос к базе:
SELECT name, cp.p_count FROM catalog_category AS cc
INNER JOIN LATERAL (
  SELECT cc.id AS id, SUM(products) AS p_count FROM (
    SELECT cc.id AS parent_id, category_id, COUNT(id) AS products
    FROM catalog_product
    WHERE category_id IN (
      SELECT id FROM catalog_category
      WHERE lft <= cc.rght AND lft >= cc.lft AND tree_id = cc.tree_id)
      GROUP BY category_id
    ) AS sub_cс
  GROUP BY parent_id
) AS cp
USING(id) ORDER BY name;
Ответ написан
Astrohas
@Astrohas
Python/Django Developer
class Category(models.Model):
    parent = models.ForeignKey('self', blank=True, null=True, related_name='children')


а Для того чтобы отобразить, сделайте собственный кастом тег, который будет генерировать это на стороне питона
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы