django-fast-treenode 3.0.6__tar.gz → 3.0.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_fast_treenode-3.0.6/django_fast_treenode.egg-info → django_fast_treenode-3.0.8}/PKG-INFO +1 -1
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8/django_fast_treenode.egg-info}/PKG-INFO +1 -1
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/admin.md +0 -3
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/pyproject.toml +1 -1
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/setup.py +1 -1
- django_fast_treenode-3.0.8/treenode/__init__.py +1 -0
- django_fast_treenode-3.0.8/treenode/admin/admin.py +222 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/admin/mixin.py +1 -1
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/managers/queries.py +18 -6
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/managers/tasks.py +1 -1
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/models.py +2 -2
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/css/treenode_admin.css +21 -0
- django_fast_treenode-3.0.8/treenode/static/js/treenode_admin.js +322 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/AUTHORS.txt +384 -384
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/LICENSE.txt +43 -43
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/external/jquery/jquery.js +10716 -10716
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/index.html +297 -297
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/jquery-ui.css +438 -438
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/jquery-ui.js +5222 -5222
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/jquery-ui.min.css +6 -6
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/jquery-ui.min.js +5 -5
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/jquery-ui.structure.css +16 -16
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/jquery-ui.structure.min.css +4 -4
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/jquery-ui.theme.css +439 -439
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/jquery-ui.theme.min.css +4 -4
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/package.json +82 -82
- django_fast_treenode-3.0.8/treenode/templates/treenode/admin/treenode_changelist.html +71 -0
- django_fast_treenode-3.0.8/treenode/templates/treenode/admin/treenode_rows.html +54 -0
- django_fast_treenode-3.0.8/treenode/templatetags/treenode_admin.py +89 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/utils/db/sqlcompat.py +1 -33
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/utils/db/sqlquery.py +0 -24
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/version.py +2 -2
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/views/autoapi.py +91 -91
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/views/autocomplete.py +52 -52
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/views/children.py +41 -41
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/views/common.py +23 -23
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/widgets.py +0 -2
- django_fast_treenode-3.0.6/treenode/admin/admin.py +0 -226
- django_fast_treenode-3.0.6/treenode/static/js/treenode_admin.js +0 -531
- django_fast_treenode-3.0.6/treenode/templates/treenode/admin/treenode_changelist.html +0 -25
- django_fast_treenode-3.0.6/treenode/templates/treenode/admin/treenode_rows.html +0 -57
- django_fast_treenode-3.0.6/treenode/templatetags/treenode_admin.py +0 -46
- django_fast_treenode-3.0.6/treenode/utils/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/LICENSE +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/MANIFEST.in +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/README.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/django_fast_treenode.egg-info/SOURCES.txt +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/django_fast_treenode.egg-info/dependency_links.txt +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/django_fast_treenode.egg-info/requires.txt +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/django_fast_treenode.egg-info/top_level.txt +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/.gitignore +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/.nojekyll +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/about.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/api.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/apifirst.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/cache.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/customization.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/dnd.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/import_export.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/index.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/insert-after.jpg +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/insert-as-child.jpg +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/installation.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/migration.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/models.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/requirements.txt +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/roadmap.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/docs/using.md +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/setup.cfg +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/tests/test_suite.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/admin/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/admin/changelist.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/admin/exporter.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/admin/importer.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/apps.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/cache.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/forms.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/managers/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/managers/managers.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/decorators.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/factory.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/ancestors.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/children.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/descendants.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/family.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/logical.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/node.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/properties.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/roots.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/siblings.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/tree.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/models/mixins/update.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/settings.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/signals.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/.gitkeep +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/css/.gitkeep +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/css/tree_widget.css +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/css/treenode_tabs.css +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/js/.gitkeep +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/js/lz-string.min.js +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/js/tree_widget.js +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/images/ui-icons_444444_256x240.png +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/images/ui-icons_555555_256x240.png +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/images/ui-icons_777620_256x240.png +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/images/ui-icons_777777_256x240.png +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/images/ui-icons_cc0000_256x240.png +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/vendors/jquery-ui/images/ui-icons_ffffff_256x240.png +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/templates/.gitkeep +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/templates/treenode/.gitkeep +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/templates/treenode/admin/.gitkeep +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/templates/treenode/admin/treenode_ajax_rows.html +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/templates/treenode/admin/treenode_import_export.html +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/templates/treenode/widgets/tree_widget.html +0 -0
- {django_fast_treenode-3.0.6/treenode → django_fast_treenode-3.0.8/treenode/templatetags}/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/tests.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/urls.py +0 -0
- {django_fast_treenode-3.0.6/treenode/templatetags → django_fast_treenode-3.0.8/treenode/utils}/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/utils/db/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/utils/db/compiler.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/utils/db/db_vendor.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/utils/db/service.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/views/__init__.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/views/crud.py +0 -0
- {django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/views/search.py +0 -0
@@ -16,7 +16,6 @@ class CategoryAdmin(TreeNodeModelAdmin):
|
|
16
16
|
# Set the display mode: 'accordion', 'breadcrumbs', or 'indentation'
|
17
17
|
treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_ACCORDION
|
18
18
|
# treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_BREADCRUMBS
|
19
|
-
# treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_INDENTATION
|
20
19
|
|
21
20
|
list_display = ("name",)
|
22
21
|
search_fields = ("name",)
|
@@ -30,8 +29,6 @@ You can choose from three display modes:
|
|
30
29
|
Expands/collapses nodes dynamically.
|
31
30
|
- **`TREENODE_DISPLAY_MODE_BREADCRUMBS`**
|
32
31
|
Displays the tree as a sequence of **breadcrumbs**, making it easy to navigate.
|
33
|
-
- **`TREENODE_DISPLAY_MODE_INDENTATION`**
|
34
|
-
Uses a **long dash** (`———`) to indicate nesting levels, providing a simple visual structure.
|
35
32
|
|
36
33
|
The accordion mode is **always active**, and the setting only affects how nodes are displayed.
|
37
34
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "django-fast-treenode"
|
7
|
-
version = "3.0.
|
7
|
+
version = "3.0.8"
|
8
8
|
description = "Treenode Framework for supporting tree (hierarchical) data structure in Django projects"
|
9
9
|
readme = "README.md"
|
10
10
|
authors = [{ name = "Timur Kady", email = "timurkady@yandex.com" }]
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
2
2
|
|
3
3
|
setup(
|
4
4
|
name='django-fast-treenode',
|
5
|
-
version='3.0.
|
5
|
+
version='3.0.8',
|
6
6
|
description='Treenode Framework for supporting tree (hierarchical) data structure in Django projects',
|
7
7
|
long_description=open('README.md', encoding='utf-8').read(),
|
8
8
|
long_description_content_type='text/markdown',
|
@@ -0,0 +1 @@
|
|
1
|
+
default_app_config = 'treenode.apps.TreeNodeConfig'
|
@@ -0,0 +1,222 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
TreeNode Admin Model Class
|
4
|
+
|
5
|
+
Modified admin panel for django-fast-treenode. Solves the following problems:
|
6
|
+
- Set list_per_page = 10000 to display all elements at once.
|
7
|
+
- Hidden standard pagination via CSS
|
8
|
+
- Disabled counting the total number of elements to speed up loading
|
9
|
+
- Accordion works regardless of the display mode
|
10
|
+
Two modes are supported:
|
11
|
+
- Indented - with indents and icons
|
12
|
+
- Breadcrumbs - with breadcrumbs
|
13
|
+
All modes have links to editing objects.
|
14
|
+
|
15
|
+
- Expand buttons for nodes with children
|
16
|
+
|
17
|
+
Additional features:
|
18
|
+
- Control panel with "Expand All" / "Collapse All" buttons
|
19
|
+
- Saving the state of the tree between page transitions
|
20
|
+
- Smooth animations when expanding/collapsing
|
21
|
+
- Counting the total number of nodes in the tree
|
22
|
+
- Recursive hiding of grandchildren when collapsing the parent
|
23
|
+
|
24
|
+
Version: 3.1.0
|
25
|
+
Author: Timur Kady
|
26
|
+
Email: timurkady@yandex.com
|
27
|
+
"""
|
28
|
+
|
29
|
+
|
30
|
+
from django.contrib import admin
|
31
|
+
from django.db import models
|
32
|
+
from django.urls import reverse
|
33
|
+
from django.utils.html import escape
|
34
|
+
from django.utils.safestring import mark_safe
|
35
|
+
from django.utils.translation import gettext_lazy as _
|
36
|
+
|
37
|
+
from .mixin import AdminMixin
|
38
|
+
from ..forms import TreeNodeForm
|
39
|
+
from ..widgets import TreeWidget
|
40
|
+
from .importer import TreeNodeImporter
|
41
|
+
from .exporter import TreeNodeExporter
|
42
|
+
|
43
|
+
import logging
|
44
|
+
|
45
|
+
logger = logging.getLogger(__name__)
|
46
|
+
|
47
|
+
|
48
|
+
class TreeNodeModelAdmin(AdminMixin, admin.ModelAdmin):
|
49
|
+
"""Admin for TreeNodeModel."""
|
50
|
+
|
51
|
+
# Режимы отображения
|
52
|
+
TREENODE_DISPLAY_MODE_ACCORDION = 'accordion'
|
53
|
+
TREENODE_DISPLAY_MODE_BREADCRUMBS = 'breadcrumbs'
|
54
|
+
treenode_display_mode = TREENODE_DISPLAY_MODE_ACCORDION
|
55
|
+
|
56
|
+
form = TreeNodeForm
|
57
|
+
importer_class = None
|
58
|
+
exporter_class = None
|
59
|
+
ordering = []
|
60
|
+
|
61
|
+
formfield_overrides = {
|
62
|
+
models.ForeignKey: {'widget': TreeWidget()},
|
63
|
+
}
|
64
|
+
|
65
|
+
change_list_template = "treenode/admin/treenode_changelist.html"
|
66
|
+
import_export = True
|
67
|
+
|
68
|
+
class Media:
|
69
|
+
"""Meta Class."""
|
70
|
+
|
71
|
+
css = {"all": (
|
72
|
+
"css/treenode_admin.css",
|
73
|
+
"vendors/jquery-ui/jquery-ui.css",
|
74
|
+
)}
|
75
|
+
js = (
|
76
|
+
"vendors/jquery-ui/jquery-ui.js",
|
77
|
+
# "js/lz-string.min.js",
|
78
|
+
"js/treenode_admin.js",
|
79
|
+
)
|
80
|
+
|
81
|
+
def __init__(self, model, admin_site):
|
82
|
+
"""Init method."""
|
83
|
+
super().__init__(model, admin_site)
|
84
|
+
|
85
|
+
if not self.list_display:
|
86
|
+
self.list_display = [field.name for field in model._meta.fields]
|
87
|
+
|
88
|
+
self.TreeNodeImporter = self.importer_class or TreeNodeImporter
|
89
|
+
self.TreeNodeExporter = self.exporter_class or TreeNodeExporter
|
90
|
+
|
91
|
+
def drag(self, obj):
|
92
|
+
"""Drag and drop сolumn."""
|
93
|
+
return mark_safe('<span class="treenode-drag-handle">☰</span>')
|
94
|
+
|
95
|
+
drag.short_description = _("Move")
|
96
|
+
|
97
|
+
def toggle(self, obj):
|
98
|
+
"""Toggle column."""
|
99
|
+
if obj.get_children_count() > 0:
|
100
|
+
return mark_safe(
|
101
|
+
f'<button class="treenode-toggle" data-node-id="{obj.pk}">►</button>' # noqa
|
102
|
+
)
|
103
|
+
return mark_safe('<div class="treenode-space"> </div>')
|
104
|
+
|
105
|
+
toggle.short_description = _("Expand")
|
106
|
+
|
107
|
+
def get_changelist(self, request, **kwargs):
|
108
|
+
"""Get changelist."""
|
109
|
+
ChangeList = super().get_changelist(request, **kwargs)
|
110
|
+
|
111
|
+
class NoPaginationChangeList(ChangeList):
|
112
|
+
"""Suppress pagination."""
|
113
|
+
|
114
|
+
def get_results(self, request):
|
115
|
+
"""Get result."""
|
116
|
+
super().get_results(request)
|
117
|
+
self.paginator.show_all = True
|
118
|
+
self.result_count = len(self.result_list)
|
119
|
+
self.full_result_count = len(self.result_list)
|
120
|
+
self.can_show_all = False
|
121
|
+
self.multi_page = False
|
122
|
+
self.actions = self.model_admin.get_actions(request)
|
123
|
+
|
124
|
+
return NoPaginationChangeList
|
125
|
+
|
126
|
+
def get_changelist_instance(self, request):
|
127
|
+
"""
|
128
|
+
Get changelist instance.
|
129
|
+
|
130
|
+
Make sure our custom ChangeList is used without pagination.
|
131
|
+
"""
|
132
|
+
ChangeList = self.get_changelist(request)
|
133
|
+
|
134
|
+
return ChangeList(
|
135
|
+
request,
|
136
|
+
self.model,
|
137
|
+
self.get_list_display(request),
|
138
|
+
self.get_list_display_links(
|
139
|
+
request,
|
140
|
+
self.get_list_display(request)
|
141
|
+
),
|
142
|
+
self.get_list_filter(request),
|
143
|
+
self.date_hierarchy,
|
144
|
+
self.search_fields,
|
145
|
+
self.list_select_related,
|
146
|
+
self.list_per_page,
|
147
|
+
self.list_max_show_all,
|
148
|
+
self.list_editable,
|
149
|
+
self,
|
150
|
+
sortable_by=self.get_sortable_by(request),
|
151
|
+
search_help_text=self.get_search_help_text(request),
|
152
|
+
)
|
153
|
+
|
154
|
+
def get_queryset(self, request):
|
155
|
+
"""Get queryset."""
|
156
|
+
qs = super().get_queryset(request)
|
157
|
+
return qs.select_related('parent')\
|
158
|
+
.prefetch_related('children')\
|
159
|
+
.order_by('_path')
|
160
|
+
|
161
|
+
def get_list_display(self, request):
|
162
|
+
"""Get list_display."""
|
163
|
+
def treenode_field(obj):
|
164
|
+
return self._get_treenode_field_display(request, obj)
|
165
|
+
|
166
|
+
description = str(self.model._meta.verbose_name)
|
167
|
+
treenode_field.short_description = description
|
168
|
+
|
169
|
+
return (self.drag, self.toggle, treenode_field)
|
170
|
+
|
171
|
+
def get_form(self, request, obj=None, **kwargs):
|
172
|
+
"""Get Form method."""
|
173
|
+
form = super().get_form(request, obj, **kwargs)
|
174
|
+
if "parent" in form.base_fields:
|
175
|
+
form.base_fields["parent"].widget = TreeWidget()
|
176
|
+
return form
|
177
|
+
|
178
|
+
def get_search_fields(self, request):
|
179
|
+
"""Get search fields."""
|
180
|
+
return [getattr(self.model, 'display_field', 'id') or 'id']
|
181
|
+
|
182
|
+
def _get_treenode_field_display(self, request, obj):
|
183
|
+
"""
|
184
|
+
Generate HTML to display tree nodes.
|
185
|
+
|
186
|
+
Depending on the selected display mode (accordion or breadcrumbs),
|
187
|
+
do the following:
|
188
|
+
- For accordion mode: add indents and icons.
|
189
|
+
- For breadcrumbs mode: display breadcrumb path.
|
190
|
+
"""
|
191
|
+
level = obj.get_depth()
|
192
|
+
display_field = getattr(obj, "display_field", None)
|
193
|
+
edit_url = reverse(
|
194
|
+
f"admin:{obj._meta.app_label}_{obj._meta.model_name}_change",
|
195
|
+
args=[obj.pk]
|
196
|
+
)
|
197
|
+
icon = ""
|
198
|
+
text = ""
|
199
|
+
padding = ""
|
200
|
+
closing = ""
|
201
|
+
|
202
|
+
if self.treenode_display_mode == self.TREENODE_DISPLAY_MODE_ACCORDION:
|
203
|
+
icon = "📄 " if obj.is_leaf() else "📁 "
|
204
|
+
text = getattr(obj, display_field, str(obj))
|
205
|
+
padding = f'<span style="padding-left: {level * 1.5}em;">'
|
206
|
+
closing = "</span>"
|
207
|
+
elif self.treenode_display_mode == self.TREENODE_DISPLAY_MODE_BREADCRUMBS: # noqa
|
208
|
+
if display_field:
|
209
|
+
breadcrumbs = obj.get_breadcrumbs(attr=display_field)
|
210
|
+
else:
|
211
|
+
breadcrumbs = [str(item) for item in obj.get_ancestors()]
|
212
|
+
|
213
|
+
text = "/" + "/".join([escape(label) for label in breadcrumbs])
|
214
|
+
|
215
|
+
content = f'{padding}{icon}<a href="{edit_url}">{escape(text)}</a>{closing}' # noqa
|
216
|
+
return mark_safe(content)
|
217
|
+
|
218
|
+
def get_list_per_page(self, request):
|
219
|
+
"""Get list per page."""
|
220
|
+
return 999999
|
221
|
+
|
222
|
+
# The End
|
@@ -5,14 +5,13 @@ Low-level SQL Query Manager.
|
|
5
5
|
Encapsulates all logic to retrieve related primary keys based on relationships
|
6
6
|
(e.g., ancestors, children, descendants, siblings, family, root) using raw SQL.
|
7
7
|
|
8
|
-
Version: 3.0.
|
8
|
+
Version: 3.0.0
|
9
9
|
Author: Timur Kady
|
10
10
|
Email: timurkady@yandex.com
|
11
11
|
"""
|
12
12
|
|
13
13
|
|
14
14
|
from django.db import connection
|
15
|
-
from ..utils.db.sqlcompat import SQLCompat
|
16
15
|
|
17
16
|
|
18
17
|
class TreeQuery:
|
@@ -33,6 +32,19 @@ class TreeQuery:
|
|
33
32
|
cursor.execute(sql, params)
|
34
33
|
return cursor.fetchall()
|
35
34
|
|
35
|
+
def wrap_union_all(self, queries):
|
36
|
+
"""
|
37
|
+
Combine multiple SQL queries using UNION ALL.
|
38
|
+
|
39
|
+
Each query is a tuple: (sql, params).
|
40
|
+
Returns a tuple: (combined_sql, combined_params).
|
41
|
+
"""
|
42
|
+
union_query = " UNION ALL ".join(f"({q[0]})" for q in queries)
|
43
|
+
combined_params = []
|
44
|
+
for q in queries:
|
45
|
+
combined_params.extend(q[1])
|
46
|
+
return union_query, combined_params
|
47
|
+
|
36
48
|
def order_by(self, sql, order_by_clause):
|
37
49
|
"""Wrap the SQL in an outer query to enforce ordering."""
|
38
50
|
return f"SELECT * FROM ({sql}) AS combined ORDER BY {order_by_clause}"
|
@@ -64,7 +76,7 @@ class TreeQuery:
|
|
64
76
|
if include_self:
|
65
77
|
sql2 = f"SELECT id, priority FROM {self.db_table} WHERE id = %s"
|
66
78
|
params2 = [self.node.pk]
|
67
|
-
combined_sql, combined_params =
|
79
|
+
combined_sql, combined_params = self.wrap_union_all(
|
68
80
|
[(sql1, params1), (sql2, params2)])
|
69
81
|
sql = self.order_by(combined_sql, "priority")
|
70
82
|
return sql, combined_params
|
@@ -103,7 +115,7 @@ class TreeQuery:
|
|
103
115
|
FROM {self.db_table}
|
104
116
|
WHERE id = %s
|
105
117
|
"""
|
106
|
-
union_sql, union_params =
|
118
|
+
union_sql, union_params = self.wrap_union_all([
|
107
119
|
(base_sql, params),
|
108
120
|
(sql_self, [self.node.pk])
|
109
121
|
])
|
@@ -136,7 +148,7 @@ class TreeQuery:
|
|
136
148
|
|
137
149
|
if include_self:
|
138
150
|
sql_self = f"SELECT id, _depth, priority FROM {self.db_table} WHERE id = %s" # noqa: D501
|
139
|
-
union_sql, union_params =
|
151
|
+
union_sql, union_params = self.wrap_union_all(
|
140
152
|
[(base_sql, params), (sql_self, [self.node.pk])])
|
141
153
|
else:
|
142
154
|
union_sql, union_params = base_sql, params
|
@@ -186,7 +198,7 @@ class TreeQuery:
|
|
186
198
|
if include_self:
|
187
199
|
sql_self = f"SELECT id, _depth, priority FROM {self.db_table} WHERE id = %s" # noqa: D501
|
188
200
|
queries.append((sql_self, [self.node.pk]))
|
189
|
-
combined_sql, combined_params =
|
201
|
+
combined_sql, combined_params = self.wrap_union_all(queries)
|
190
202
|
combined_sql = self.order_by(combined_sql, "_depth, priority")
|
191
203
|
return combined_sql, combined_params
|
192
204
|
|
@@ -14,7 +14,7 @@ Features:
|
|
14
14
|
- Provides a caching mechanism to optimize performance.
|
15
15
|
- Includes methods for tree traversal, manipulation, and serialization.
|
16
16
|
|
17
|
-
Version: 3.0.
|
17
|
+
Version: 3.0.7
|
18
18
|
Author: Timur Kady
|
19
19
|
Email: timurkady@yandex.com
|
20
20
|
|
@@ -122,7 +122,7 @@ class TreeNodeModel(
|
|
122
122
|
|
123
123
|
def __str__(self):
|
124
124
|
"""Return a human-readable string representation of an object."""
|
125
|
-
field = getattr(
|
125
|
+
field = getattr(self, 'display_field', None)
|
126
126
|
if field and hasattr(self, field):
|
127
127
|
return str(getattr(self, field))
|
128
128
|
return f'Node {self.pk}'
|
{django_fast_treenode-3.0.6 → django_fast_treenode-3.0.8}/treenode/static/css/treenode_admin.css
RENAMED
@@ -66,6 +66,27 @@ Email: timurkady@yandex.com
|
|
66
66
|
opacity: 1.0;
|
67
67
|
}
|
68
68
|
|
69
|
+
.treenode-toolbar{
|
70
|
+
display: flex;
|
71
|
+
}
|
72
|
+
|
73
|
+
.treenode-toolbar {
|
74
|
+
margin: 15px 0px;
|
75
|
+
}
|
76
|
+
|
77
|
+
.treenode-button {
|
78
|
+
padding: 5px !important;
|
79
|
+
margin-left: 15px !important;
|
80
|
+
}
|
81
|
+
|
82
|
+
tr.treenode-hidden {
|
83
|
+
display: none;
|
84
|
+
}
|
85
|
+
|
86
|
+
td.action-checkbox{
|
87
|
+
text-align: center;
|
88
|
+
}
|
89
|
+
|
69
90
|
.dark-theme .treenode-toggle {
|
70
91
|
color: #ccc;
|
71
92
|
background-color: #444;
|