快速且简单的树形结构。
项目描述
⚠ 开放融资以支持MySQL & SQLite兼容性 ⚠
快速且简单的树形结构。
处于测试阶段,目前还不能用于生产。
这个工具的工作方式与 django-mptt 和 django-treebeard 非常相似,然而由于它在构思上有所不同,从头开始比重写现有解决方案更好更快。
与这些解决方案相比,django-tree旨在具有以下优势(其中一些已经实现)
更少侵入性(没有由于模型、管理器和查询集子类引起的继承问题)
更容易安装
更容易使用
更完整
极简主义(代码更少,数据库字段更少)
无错误
安全(大部分逻辑直接写入数据库)
所有操作更快
然而,这里没有突破性的东西:这仅仅是最新Django改进的正确使用和良好SQL知识的结果。
基准测试
详细的基准测试 可以给出django-tree与其他Django解决方案相比的性能的良好概念。同时它更易于使用,更健壮,并且完全通用到原始SQL,批量等。
基准测试的一些值得注意的摘录(越少越好)
安装
Django-tree需要Django 1.8、1.11或2.0以及Python 2或3。目前,django-tree仅适用于PostgreSQL。将来将适应其他数据库。
安装模块后,您需要将'tree'添加到您的INSTALLED_APPS中,然后在具有ForeignKey('self')(通常命名为parent)的模型中添加一个PathField(如果该字段有其他名称,请使用CreateTreeTrigger的parent_field参数)。PathField存储Path对象,这些对象有执行查询的方法,例如获取当前对象的全部子代、其兄弟等。为了更方便地调用这些方法,您可以将TreeModelMixin添加到您的模型中。混合继承顺序并不重要,因为混合方法不会与Django冲突。如果您在同一个模型上有多个PathField,您必须在调用方法时指定字段名称,使用path_field。
这将为您提供如下所示的模型
from django.db.models import Model, CharField, ForeignKey, BooleanField
from tree.fields import PathField
from tree.models import TreeModelMixin
class YourModel(Model, TreeModelMixin):
name = CharField(max_length=30)
parent = ForeignKey('self', null=True, blank=True)
path = PathField()
public = BooleanField(default=False)
class Meta:
ordering = ['path']
然后您需要创建一个SQL触发器,该触发器将自动更新path。为此,创建一个依赖最新django-tree迁移的迁移,并添加一个CreateTreeTrigger操作
from django.db import migrations
from tree.operations import CreateTreeTrigger
class Migration(migrations.Migration):
dependencies = [
('tree', '0001_initial'),
]
operations = [
CreateTreeTrigger('your_app.YourModel'),
]
如果您已经在YourModel中有了数据,您将需要添加一个操作来允许SQLNULL值,然后在创建触发器之前重新构建路径,并撤销对NULL值的允许
from django.db import migrations
from tree.fields import PathField
from tree.operations import CreateTreeTrigger, RebuildPaths
class Migration(migrations.Migration):
dependencies = [
('tree', '0001_initial'),
]
operations = [
migrations.AlterField('YourModel', 'path', PathField(null=True)),
CreateTreeTrigger('YourModel'),
RebuildPaths('YourModel', 'path'),
migrations.AlterField('YourModel', 'path', PathField()),
]
然而,上述模型是无序的。相同父级的子代将按主键排序。您可以使用PathField的order_by参数来指定子代的排序方式。如果需要,您可以为用户添加一个字段来明确排序这些对象,通常是一个位置字段。示例模型
from django.db.models import (
Model, CharField, ForeignKey, IntegerField, BooleanField)
from tree.fields import PathField
from tree.models import TreeModelMixin
class YourModel(Model, TreeModelMixin):
name = CharField(max_length=30)
parent = ForeignKey('self', null=True, blank=True)
position = IntegerField(default=1)
path = PathField(order_by=['position', 'name'])
public = BooleanField(default=False)
class Meta:
ordering = ['path']
相应的迁移如下
from django.db import models, migrations
from tree.operations import CreateTreeTrigger
class Migration(migrations.Migration):
dependencies = [
('tree', '0001_initial'),
]
operations = [
migrations.AddField('YourModel', 'position',
models.IntegerField(default=1))
CreateTreeTrigger('YourModel'),
]
在这里,相同父级的子代将按位置排序,如果位置相同,则按名称排序。
用法
由于有CreateTreeTrigger,PathField将自动填充,一旦安装,您就无需设置、修改或查看其值。但您可以使用它存储的Path对象或更方便的TreeModelMixin来获取当前实例的树信息,或在整个树结构上执行复杂的查询。以下示例展示了大部分可能性
obj = YourModel.objects.all()[0]
obj.path.get_level()
obj.get_level() # Shortcut for the previous method, if you use
# `TreeModelMixin`. Same for other object methods below.
obj.is_root()
obj.is_leaf()
obj.get_children()
obj.get_children().filter(public=True)
obj.get_ancestors()
obj.get_ancestors(include_self=True)
obj.get_descendants(include_self=True)
obj.get_siblings()
obj.get_prev_sibling() # Fetches the previous sibling.
obj.get_next_sibling()
# Same as `get_prev_sibling`, except that we get the first public one.
obj.get_prev_siblings().filter(public=True).first()
other = YourModel.objects.all()[1]
obj.is_ancestor_of(other)
obj.is_descendant_of(other, include_self=True)
YourModel.objects.filter_roots()
#
# Advanced usage
# Use the following methods only if you understand exactly what they mean.
#
YourModel.rebuild_paths() # Rebuilds all paths of this field, useful only
# if something is broken, which shouldn’t happen.
YourModel.disable_tree_trigger() # Disables the SQL trigger.
YourModel.enable_tree_trigger() # Restores the SQL trigger.
with YourModel.disabled_tree_trigger():
# What happens inside this context manager is ignored
# by the SQL trigger.
# The trigger is restored after that, even if there an error occurred.
pass
还有一些不太有用的查找和转换可用。它们将在将来通过示例进行说明。
MPTT和treebeard的差异
级别 vs 深度
django-mptt和django-treebeard使用两个不同的名称来表示几乎相同的东西:MPTT使用级别,treebeard使用深度。它们都是整数,用于表示节点与树顶部的距离。唯一的区别是,根据惯例,级别应该从1开始,而深度应该从0开始。
遗憾的是,MPTT和treebeard在索引方面都是错误的:MPTT从级别0开始,而treebeard从深度1开始。
Django-tree最终通过从1级开始实现级别来解决这个问题,并且没有深度以避免混淆。必须选择一个名称,我发现“级别”更能准确地表达我们处理的是一个抽象树,其中同一级别的所有节点都在同一行。相比之下,“深度”听起来像我们实际上正在挖掘一个真正的根,给人一种根的子节点可以比另一个根的子节点深的感觉,就像在现实生活中一样。
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。
源代码分发
构建版本
django-tree-0.5.6.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 0b9d5ee82b162ccdad446c84a29732cab4acb47cdbb3e83c755a4774f677e68a |
|
MD5 | b93315d864cacf26aa4d0e3516d996e8 |
|
BLAKE2b-256 | 8a86a30698769900e0a4188fad5671fd8afa82b19cf0d4f76f184e3481387003 |
django_tree-0.5.6-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 48fdc787f3d38dda02bb67f9e9c4992b3b948462463f260b232379b516b1176a |
|
MD5 | 8441372c654877bfd80dfe44ebc73c6c |
|
BLAKE2b-256 | 73451df8787e651f9b7de61972aa7aa71db56a40ad2f7769ade39474e57a6971 |