利用 Django QuerySet 创建 Python 中的基础树形结构

86 阅读2分钟

我需要根据包含四个字段(A、B、C 和 D)的表创建一个基于这些字段的无序列表树。最终,它将看起来像这样:

huake_00257_.jpg

这是一个非常基本的 4 级树。我希望只用一次数据库调用来实现,但不确定是否可行。我将使用 Django QuerySet 获取数据,并且可以使用 Python。我不知道如何编写编程逻辑才能避免它变得难以控制。

2、解决方案

虽然我们可以手动编写代码来创建树形结构,但这非常复杂且容易出错。幸运的是,Django 社区已经开发了一些应用程序来简化此过程,例如 django-mpttdjango-treebeard。这些应用程序提供了用于存储和查询分层数据的模型和帮助程序。

首先,我们需要在 Django 模型中定义我们的树状结构。例如,我们可以在 models.py 文件中创建以下模型:

from django.db import models
from django.contrib.postgres.fields import ArrayField

class TreeNode(models.Model):
    name = models.CharField(max_length=255)
    parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True)
    children = ArrayField(models.IntegerField(), default=list)

    def __str__(self):
        return self.name


此模型定义了一个名为 TreeNode 的树状结构,它包含以下字段:

  • id:自动生成的唯一标识符。
  • name:树节点的名称。
  • parent:指向该节点的父节点的ForeignKey。
  • children:一个包含该节点的所有子节点ID的数组字段。

然后,我们可以使用 Django 的 QuerySet API 来查询我们的树状结构。例如,我们可以使用以下代码获取所有根节点(即没有父节点的节点):

root_nodes = TreeNode.objects.filter(parent=None)

我们可以使用 get_descendants() 方法来获取节点的所有子节点。例如,我们可以使用以下代码获取节点 1的所有子节点:

node_1 = TreeNode.objects.get(id=1)
descendants = node_1.get_descendants()

最后,我们可以使用 get_ancestors() 方法来获取节点的所有父节点。例如,我们可以使用以下代码获取节点 5的所有父节点:

node_5 = TreeNode.objects.get(id=5)
ancestors = node_5.get_ancestors()

我们可以使用这些方法来构建我们的树形结构。例如,我们可以使用以下代码构建一个包含所有节点及其子节点的字典:

def build_tree():
    tree = {}
    for node in TreeNode.objects.all():
        tree[node.id] = {
            'name': node.name,
            'children': node.children,
        }
    return tree


# Get the tree
tree = build_tree()

然后,我们可以使用此字典来创建我们的无序列表树。例如,我们可以使用以下代码创建 HTML 无序列表:

<ul>
{% for node in tree %}
    <li>{{ node.name }}
    {% if node.children %}
        <ul>
        {% for child in node.children %}
            <li>{{ child.name }}</li>
        {% endfor %}
        </ul>
    {% endif %}
    </li>
{% endfor %}
</ul>

这种方法可以轻松地创建和维护树形结构。我们可以使用 Django 的 QuerySet API 来查询我们的树,并使用 build_tree() 函数来构建一个包含所有节点及其子节点的字典。然后,我们可以使用此字典来创建我们的无序列表树。