我有一个看起来像这样的模型:
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,则它是根类别。
我用它来构建类别层次结构。
什么是最有效的方法:
出于某种原因,
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
不胜感激任何帮助。
谢谢!
一个可能的解决方案可以使用https://django-mptt.readthedocs.io/en/latest/overview.html#what-is-django-mptt
MPTT 是一种在数据库中存储分层数据的技术。这 目的是使检索操作非常有效。 这种效率的权衡是在树周围执行插入和移动项目更加复杂,因为需要一些额外的工作来始终保持树结构处于良好状态。
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
name = models.CharField(max_length=50)
slug = models.SlugField()
parent = TreeForeignKey(
'self',
null=True,
blank=True,
on_delete=models.CASCADE,
related_name='children'
)
class MPTTMeta:
order_insertion_by = ['name']
您可以像这样使用 django-mptt 模板标签:
{% load mptt_tags %}
<ul>
{% recursetree categories %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
图书馆文档中有教程和更多信息。
我遇到了同样的问题,最终创建了以下函数,该函数访问数据库一次,然后整理出层次结构并返回一个字典:
def get_category_tree():
categories = Category.objects.order_by('name')
itemtree = {}
# Add 'children' attribute to each category; populate dict
for category in categories:
category.children = {}
itemtree[category.pk] = category
# Add categories to 'children'
for key,value in itemtree.items():
if value.parent_id:
itemtree[value.parent_id].children[key] = value
# Return top-level items
return {k:v for k,v in itemtree.items() if not v.parent_id}
返回的字典的每个
value
都是一个顶级类别对象,它有一个children
属性。
您可以通过遍历字典值在模板中呈现它。以下示例将处理三个级别的层次结构:
<ul>
{% for level1 in category_tree.values %}
<li>
{{ level1.name }}
{% if level1.children %}
<ul>
{for level2 in level1.children.values %}
<li>{{ level2.name }}
{% if level2.children %}
<ul>
{for level3 in level2.children.values %}
<li>{{ level3.name }}</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
如果你需要渲染多层次的层次结构,你可以考虑使用模板递归。阅读以下问题和答案以确定是否合适:Represent a tree of objects in Django template