Django PostgreSQL -高效地获取递归类别结构

lmvvr0a8  于 2022-12-03  发布在  PostgreSQL
关注(0)|答案(1)|浏览(89)
    • bounty将在6天后过期**。回答此问题可获得+100的声望奖励。OhMad正在寻找来自知名来源的答案

我有一个模型,看起来像这样:

class Category(models.Model):
    name = models.CharField(max_length=50)
    slug = models.SlugField()
    parent = models.ForeignKey(
        'categories.Category',
        null=True,
        blank=True,
        on_delete=models.CASCADE,
        related_name='categories'
    )

基本上,在parent字段中,它引用自身。如果父类别设置为None,则它是根类别。
我用它来建立类别的层次结构。
最有效的方法是什么:
1.通过层次结构获取所有对象
1.在模板中显示它们?
出于某种原因,select_related在这里似乎并没有带来性能的改进。
我还发现了这个:How to recursively query in django efficiently?
但是我很难把它应用到我的例子中,因为我仍然不明白到底发生了什么。这是我的结果:

WITH RECURSIVE hierarchy(slug, parent_id) AS (
        SELECT slug, parent_id 
        FROM categories_category
        WHERE parent_id = '18000'

        UNION ALL

        SELECT sm.slug, sm.parent_id
        FROM categories_category AS sm, hierarchy AS h
        WHERE sm.parent_id = h.slug
        )
    SELECT * FROM hierarchy

会很感激你的帮助。
谢谢你!

tnkciper

tnkciper1#

以下是几种可能的方法,可用来最佳化查询并显示类别的阶层:
使用select_related()方法预取每个子类别的父类别。这将减少检索父类别所需的查询数,并且如果需要访问模板中每个子类别的父类别,还可以提高性能:
提取所有类别并预取其父类别

categories = Category.objects.select_related('parent')

使用prefetch_related()方法预取每个父类别的所有子类别。这将减少检索子类别所需的查询数,并且如果您需要访问模板中每个父类别的子类别,还可以提高性能:
获取所有父类别并预取其子类别

parent_categories = Category.objects.filter(parent__isnull=True).prefetch_related('categories')

使用Model.objects.raw()方法创建一个原始SQL查询,该查询在单个查询中获取类别层次结构。如果需要获取和显示大量类别,这可以提高性能,因为它避免了创建和初始化多个模型对象的开销。以下是一个获取类别层次结构的原始SQL查询示例:
创建获取类别层次结构的原始SQL查询

raw_query = """
    SELECT c.id, c.name, c.parent_id
    FROM categories_category c
    WHERE c.parent_id IS NULL
    UNION ALL
    SELECT c.id, c.name, c.parent_id
    FROM categories_category c
    INNER JOIN (
        SELECT c.id, c.name, c.parent_id
        FROM categories_category c
        WHERE c.parent_id IS NOT NULL
    ) child_categories ON child_categories.parent_id = c.id
"""

执行原始SQL查询并获取类别层次结构

categories = Category.objects.raw(raw_query)

在模板中,您可以使用递归模板标记来显示类别的层次结构。以下是如何执行此操作的示例:

{% load recursive_tags %}

<ul>
    {% recursetree categories %}
        <li>
            {{ node.name }}
            {% if not node.is_leaf_node %}
                <ul>
                    {{ children }}
                </ul>
            {% endif %}
        </li>
    {% endrecursetree %}
</ul>

注意必须安装并加载django-mptt库才能使用recursetree模板标签。请参考文档以了解更多关于如何使用递归模板标签的信息。

相关问题