Django приложение для создания древовидных меню с возможностью редактирования через админ-панель. Реализовано с использованием template tags и оптимизировано для минимального количества запросов к БД.
✅ Template Tag - Меню реализовано через {% draw_menu 'menu_name' %}
✅ Умное раскрытие - Все элементы над активным пунктом развернуты, первый уровень под активным тоже
✅ База данных - Хранение в PostgreSQL с древовидной структурой
✅ Админ-панель - Полное редактирование через стандартную админку Django
✅ Активный пункт - Определяется автоматически по URL текущей страницы
✅ Множество меню - Несколько меню на одной странице по разным названиям
✅ Гибкие URL - Поддержка как явных URL, так и named URL
✅ Оптимизация - Ровно 1 запрос к БД на отрисовку каждого меню
- Python: 3.11+
- Django: 5.2.8
- PostgreSQL: 15+
- Deployment: gunicorn, gitlab ci/cd, system daemons
git clone https://github.com/abdullaabdukulov/django-tree-menus.git
cd django-tree-menus/
chmod +x start.sh
./start.sh devpython -m venv .venv
source .venv/bin/activate
pip install -r requirements/development.txtОтредактируйте файл .env согласно вашим настройкам
pre-commit install && pre-commit autoupdatedocker compose up -d --buildsource ./.env
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuserpython manage.py runserverОткройте в браузере: http://127.0.0.1:8000
Если вы хотите сразу получить готовое меню со структурой (например main_menu и пункты до 4-го уровня вложенности),
выполните следующие команды:
python manage.py loaddata apps/menus/fixtures/menu.json
python manage.py loaddata apps/menus/fixtures/menu_items.json{% load menu_tags %}
<!DOCTYPE html>
<html>
<head>
<title>Мой сайт</title>
</head>
<body>
<!-- Главное меню -->
{% draw_menu 'main_menu' %}
<!-- Боковое меню -->
{% draw_menu 'sidebar_menu' %}
<div class="content">
{% block content %}{% endblock %}
</div>
</body>
</html>Главная (/)
О нас (/about/)
├── Наша команда (/about/team/)
└── История (/about/history/)
Услуги (/services/)
├── Веб-разработка (/services/web/)
├── Мобильные приложения (/services/mobile/)
└── Дизайн (/services/design/)
└── UI/UX (/services/design/uiux/)
Контакты (/contacts/)
При переходе на /services/design/uiux/:
- Развернуты: Услуги → Дизайн → UI/UX
- Свернуты: О нас, Контакты
- Активный: UI/UX
python manage.py test apps.menuspython manage.py test apps.menus.tests.MenuModelTest
python manage.py test apps.menus.tests.MenuManagerTest
python manage.py test apps.menus.tests.DrawMenuTemplateTagTest- ✅ Создание и работа моделей Menu и MenuItem
- ✅ Построение дерева меню (MenuManager)
- ✅ Определение активного пункта и пути
- ✅ Отрисовка template tag
- ✅ Оптимизация запросов к БД
- ✅ Обработка edge cases
django-tree-menus/
├── .deployments/
│ ├── development/
│ │ ├── db_configs/
│ │ │ ├── Dockerfile
│ │ │ └── postgres-script.sh
│ │ ├── docker-compose.yml
│ │ └── env_example.txt
│ ├── nginx/
│ │ ├── Dockerfile
│ │ └── nginx.conf
│ ├── staging/
│ │ ├── docker-compose.yml
│ │ ├── Dockerfile
│ │ └── env_example.txt
│ └── production/
│ ├── docker-compose.yml
│ ├── Dockerfile
│ └── env_example.txt
├── apps/
│ └── menus/
│ ├── migrations/
│ ├── templatetags/
│ │ ├── __init__.py
│ │ └── menu_tags.py
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── config/
│ ├── settings/
│ │ ├── base.py
│ │ ├── development.py
│ │ ├── staging.py
│ │ └── production.py
│ ├── __init__.py
│ ├── asgi.py
│ ├── urls.py
│ └── wsgi.py
├── requirements/
│ ├── base.txt
│ ├── development.txt
│ ├── staging.txt
│ └── production.txt
├── .dockerignore
├── .env
├── .gitignore
├── .pre-commit-config.yaml
├── docker-compose.yml
├── entrypoint.sh
├── manage.py
├── pyproject.toml
├── README.md
└── start.sh
- Menu - Модель для хранения меню
- MenuItem - Модель пунктов меню с поддержкой иерархии
- MenuManager - Custom manager с методом
get_menu_tree() - MenuQuerySet - Оптимизированные запросы
{% draw_menu 'menu_name' %}- Отрисовка меню по названию- Автоматическое определение активного пункта
- Умное раскрытие веток дерева
- Полная интеграция с Django Admin
- Inline редактирование пунктов меню
- Сортировка и фильтрация
Menu.objects.get_menu_tree(menu_name, current_url)
# Возвращает готовое дерево меню с метаданнымиitem.get_url() # Возвращает URL (явный или через reverse)
item.should_show_children(parent_is_active) # Нужно ли показывать детей
item.get_css_classes() # Возвращает CSS классы для элементаПриложение использует ровно 2 SQL запроса на каждое меню:
- SELECT для получения объекта Menu
- SELECT для prefetch всех MenuItem
# В MenuManager.get_menu_tree()
menu = self.with_items().get(name=menu_name) # 2 queriesДля дополнительной оптимизации можно добавить кэширование:
from django.core.cache import cache
def get_menu_tree(self, menu_name, current_url):
cache_key = f'menu_{menu_name}_{current_url}'
cached = cache.get(cache_key)
if cached:
return cached