跳转到主要内容

可能是您基于树的数据结构最佳抽象模型和管理工具。

项目描述

django-treenode

可能是您基于树结构的最佳抽象模型和管理工具。

功能

  • 快速 - 无需查询即可获取 ancestorschildrendescendantsparentrootsiblingstree
  • 同步 - 内存中的模型实例会自动更新
  • 兼容性 - 您可以轻松地将 treenode 添加到现有项目中
  • 无依赖
  • 易于配置 - 只需扩展抽象模型/模型-admin
  • 管理集成 - 优秀的树可视化:手风琴面包屑缩进
缩进(默认) 面包屑 手风琴
treenode-admin-display-mode-indentation treenode-admin-display-mode-breadcrumbs treenode-admin-display-mode-accordion

安装

  • 运行 pip install django-treenode
  • treenode 添加到 settings.INSTALLED_APPS
  • 使您的模型继承自 treenode.models.TreeNodeModel (以下将描述)
  • 使您的模型-admin 继承自 treenode.admin.TreeNodeModelAdmin (以下将描述)
  • 运行 python manage.py makemigrationspython manage.py migrate

配置

models.py

使您的模型类继承自 treenode.models.TreeNodeModel

from django.db import models

from treenode.models import TreeNodeModel


class Category(TreeNodeModel):

    # the field used to display the model instance
    # default value 'pk'
    treenode_display_field = "name"

    name = models.CharField(max_length=50)

    class Meta(TreeNodeModel.Meta):
        verbose_name = "Category"
        verbose_name_plural = "Categories"

TreeNodeModel 抽象类为您模型添加了许多字段(以 tn_ 为前缀,以防止直接访问)和公开方法。

:warning: 如果您正在扩展已具有一些字段的模型,请确保您的模型现有字段名称与 TreeNodeModel 公开的 方法/属性 名称不冲突。


admin.py

使您的模型-admin 类继承自 treenode.admin.TreeNodeModelAdmin

from django.contrib import admin

from treenode.admin import TreeNodeModelAdmin
from treenode.forms import TreeNodeForm

from .models import Category


class CategoryAdmin(TreeNodeModelAdmin):

    # set the changelist display mode: 'accordion', 'breadcrumbs' or 'indentation' (default)
    # when changelist results are filtered by a querystring,
    # 'breadcrumbs' mode will be used (to preserve data display integrity)
    treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_ACCORDION
    # treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_BREADCRUMBS
    # treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_INDENTATION

    # use TreeNodeForm to automatically exclude invalid parent choices
    form = TreeNodeForm

admin.site.register(Category, CategoryAdmin)

settings.py

您可以通过在 settings.CACHES 中添加 treenode 条目来使用自定义缓存后端,否则将使用默认缓存后端。

CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.filebased.FileBasedCache",
        "LOCATION": "...",
    },
    "treenode": {
        "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
    },
}

使用方法

方法/属性

delete

删除节点 如果 cascade=True(默认行为),则子节点和后代节点也将被删除,否则子节点的父节点将被设置为 None(然后子节点变为根节点)

obj.delete(cascade=True)

delete_tree

删除当前节点类的整个树

cls.delete_tree()

get_ancestors

获取一个包含所有祖先的 列表(从根到父节点排序)

obj.get_ancestors()
# or
obj.ancestors

get_ancestors_count

获取 祖先数量

obj.get_ancestors_count()
# or
obj.ancestors_count

get_ancestors_pks

获取 祖先 pks 列表

obj.get_ancestors_pks()
# or
obj.ancestors_pks

get_ancestors_queryset

获取 祖先 queryset(从父节点到根节点排序)

obj.get_ancestors_queryset()

get_breadcrumbs

获取到当前节点的 面包屑(包括当前节点)

obj.get_breadcrumbs(attr=None)
# or
obj.breadcrumbs

get_children

获取一个包含所有子节点的 列表

obj.get_children()
# or
obj.children

get_children_count

获取 子节点数量

obj.get_children_count()
# or
obj.children_count

get_children_pks

获取 子节点 pks 列表

obj.get_children_pks()
# or
obj.children_pks

get_children_queryset

获取 子节点 queryset

obj.get_children_queryset()

get_depth

获取 节点深度(后代级别的数量)

obj.get_depth()
# or
obj.depth

get_descendants

获取一个包含所有后代的 列表

obj.get_descendants()
# or
obj.descendants

get_descendants_count

获取 后代数量

obj.get_descendants_count()
# or
obj.descendants_count

get_descendants_pks

获取 后代 pks 列表

obj.get_descendants_pks()
# or
obj.descendants_pks

get_descendants_queryset

获取 后代 queryset

obj.get_descendants_queryset()

get_descendants_tree

获取一个表示 模型树 的多维 dict

obj.get_descendants_tree()
# or
obj.descendants_tree

get_descendants_tree_display

获取一个表示 模型树 的多行 string

obj.get_descendants_tree_display()
# or
obj.descendants_tree_display

get_first_child

获取 第一个子节点

obj.get_first_child()
# or
obj.first_child

get_index

获取 节点索引(节点在其父节点的子节点列表中的索引)

obj.get_index()
# or
obj.index

get_last_child

获取 最后一个子节点

obj.get_last_child()
# or
obj.last_child

get_level

获取 节点级别(从1开始计数)

obj.get_level()
# or
obj.level

get_order

获取用于排序的 排序值

obj.get_order()
# or
obj.order

get_parent

获取 父节点

obj.get_parent()
# or
obj.parent

get_parent_pk

获取 父节点pk

obj.get_parent_pk()
# or
obj.parent_pk

set_parent

设置 父节点

obj.set_parent(parent_obj)

get_priority

获取 节点优先级

obj.get_priority()
# or
obj.priority

set_priority

设置 节点优先级

obj.set_priority(100)

get_root

获取当前节点的 根节点

obj.get_root()
# or
obj.root

get_root_pk

获取当前节点的 根节点pk

obj.get_root_pk()
# or
obj.root_pk

get_roots

获取包含所有根节点的 列表

cls.get_roots()
# or
cls.roots

get_roots_queryset

获取 根节点查询集

cls.get_roots_queryset()

get_siblings

获取包含所有兄弟节点的 列表

obj.get_siblings()
# or
obj.siblings

get_siblings_count

获取兄弟节点的数量

obj.get_siblings_count()
# or
obj.siblings_count

get_siblings_pks

获取兄弟节点的 pks 列表

obj.get_siblings_pks()
# or
obj.siblings_pks

get_siblings_queryset

获取兄弟节点的 查询集

obj.get_siblings_queryset()

get_tree

获取一个表示 模型树 的多维 dict

cls.get_tree()
# or
cls.tree

get_tree_display

获取一个表示 模型树 的多行 string

cls.get_tree_display()
# or
cls.tree_display

is_ancestor_of

如果当前节点是 target_obj 的 祖先,则返回 True

obj.is_ancestor_of(target_obj)

is_child_of

如果当前节点是 target_obj 的 子节点,则返回 True

obj.is_child_of(target_obj)

is_descendant_of

如果当前节点是 target_obj 的 后代,则返回 True

obj.is_descendant_of(target_obj)

is_first_child

如果当前节点是 第一个子节点,则返回 True

obj.is_first_child()

is_last_child

如果当前节点是 最后一个子节点,则返回 True

obj.is_last_child()

is_leaf

如果当前节点是 叶子节点(没有子节点),则返回 True

obj.is_leaf()

is_parent_of

如果当前节点是 target_obj 的 父节点,则返回 True

obj.is_parent_of(target_obj)

is_root

如果当前节点是 根节点,则返回 True

obj.is_root()

is_root_of

如果当前节点是 target_obj 的 根节点,则返回 True

obj.is_root_of(target_obj)

is_sibling_of

如果当前节点是 target_obj 的 兄弟节点,则返回 True

obj.is_sibling_of(target_obj)

update_tree

手动 更新树,在批量更新后非常有用

cls.update_tree()

批量操作

执行批量操作时,建议关闭信号,然后在最后触发树更新

from treenode.signals import no_signals

with no_signals():
    # execute custom bulk operations
    pass

# trigger tree update only once
YourModel.update_tree()

常见问题解答

自定义树序列化

我该如何使用自定义数据结构来序列化树?

这个问题已在这里进行了讨论。

测试

# clone repository
git clone https://github.com/fabiocaccamo/django-treenode.git && cd django-treenode

# create virtualenv and activate it
python -m venv venv && . venv/bin/activate

# upgrade pip
python -m pip install --upgrade pip

# install requirements
pip install -r requirements.txt -r requirements-test.txt

# install pre-commit to run formatters and linters
pre-commit install --install-hooks

# run tests
tox
# or
python runtests.py
# or
python -m django test --settings "tests.settings"

许可证

MIT 许可证 下发布。


支持

  • :star: 在 GitHub 上星标此项目
  • :octocat: 在 GitHub 上关注我
  • :blue_heart: 在 Twitter 上关注我
  • :moneybag: 在 Github 上赞助我

另请参阅

  • django-admin-interface - 由管理员本身定制的默认管理员界面。将弹出窗口替换为模态窗口。 🧙 ⚡

  • django-cache-cleaner - 使用管理员面板或管理命令轻松清除整个缓存或单个缓存。 🧹✨

  • django-colorfield - 模型中的简单颜色字段,在管理员中有漂亮的颜色选择器。 🎨

  • django-extra-settings - 使用 django admin 仅通过配置和管理类型化扩展设置。 ⚙️

  • django-maintenance-mode - 当维护模式开启时,显示503错误页面。 🚧 🛠️

  • django-redirects - 具有完全控制的重定向。 ↪️

  • python-benedict - 支持键列表/键路径的字典子类,I/O 快捷方式(base64、csv、json、pickle、plist、查询字符串、toml、xml、yaml)以及许多实用工具。 📘

  • python-codicefiscale - 编码/解码意大利税号 - codifica/decodifica del Codice Fiscale。 🇮🇹 💳

  • python-fontbro - 友好的字体操作。 🧢

  • python-fsutil - 懒惰开发者使用的文件系统实用工具。 🧟‍♂️

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面