Как настроить меню навигации¶
В этом документе мы обсуждаем три различных способа настройки навигационных меню сайтов django CMS.
Меню: статическое расширение пунктов меню
Прикрепить меню: Прикрепите свое меню к странице.
Модификаторы навигации: Изменение всего дерева меню
Меню¶
Создайте cms_menus.py
в вашем приложении, со следующим:
from menus.base import Menu, NavigationNode
from menus.menu_pool import menu_pool
from django.utils.translation import gettext_lazy as _
class TestMenu(Menu):
def get_nodes(self, request):
nodes = []
n = NavigationNode(_('sample root page'), "/", 1)
n2 = NavigationNode(_('sample settings page'), "/bye/", 2)
n3 = NavigationNode(_('sample account page'), "/hello/", 3)
n4 = NavigationNode(_('sample my profile page'), "/hello/world/", 4, 3)
nodes.append(n)
nodes.append(n2)
nodes.append(n3)
nodes.append(n4)
return nodes
menu_pool.register_menu(TestMenu)
Примечание
До версии 3.1 этот модуль назывался menu.py
. Пожалуйста, обновите существующие модули в соответствии с новым соглашением об именовании. Поддержка старого имени будет удалена в версии 3.5.
Если вы обновите страницу, вы должны увидеть приведенные выше пункты меню. Функция get_nodes
должна возвращать список экземпляров NavigationNode
. Функция menus.base.NavigationNode
принимает следующие аргументы:
title
Текст для узла меню
url
URL для ссылки на узел меню
id
Уникальный идентификатор для этого меню
parent_id=None
Если это дочерний узел другого узла, укажите здесь идентификатор родителя.
parent_namespace=None
Если родительский узел не из этого меню, вы можете задать ему родительское пространство имен. Пространство имен - это имя класса. В приведенном выше примере это будет:
TestMenu
attr=None
Словарь дополнительных атрибутов, которые вы можете использовать в модификаторе или в шаблоне
visible=True
Должен ли этот пункт меню быть видимым или нет
Кроме того, каждый menus.base.NavigationNode
предоставляет ряд методов, которые подробно описаны в ссылках на API NavigationNode
.
Настройка меню во время выполнения¶
Чтобы адаптировать меню в зависимости от условий запроса (скажем: анонимный/залогиненный пользователь), вы можете использовать Navigation Modifiers или воспользоваться существующими.
Например, можно добавить атрибуты {'visible_for_anonymous': False}
/{'visible_for_authenticated': False}
, распознаваемые модификатором AuthVisibility
ядра django CMS.
Полный пример:
class UserMenu(Menu):
def get_nodes(self, request):
return [
NavigationNode(_("Profile"), reverse(profile), 1, attr={'visible_for_anonymous': False}),
NavigationNode(_("Log in"), reverse(login), 3, attr={'visible_for_authenticated': False}),
NavigationNode(_("Sign up"), reverse(logout), 4, attr={'visible_for_authenticated': False}),
NavigationNode(_("Log out"), reverse(logout), 2, attr={'visible_for_anonymous': False}),
]
Прикрепить меню¶
Классы, которые расширяются из menus.base.Menu
, всегда прикрепляются к корню. Но если вы хотите, чтобы меню было прикреплено к странице CMS, вы можете сделать и это.
Вместо расширения от Menu
вам нужно расширяться от cms.menu_bases.CMSAttachMenu
и вам нужно определить имя.
Мы сделаем это на примере, приведенном выше:
from menus.base import NavigationNode
from menus.menu_pool import menu_pool
from django.utils.translation import gettext_lazy as _
from cms.menu_bases import CMSAttachMenu
class TestMenu(CMSAttachMenu):
name = _("test menu")
def get_nodes(self, request):
nodes = []
n = NavigationNode(_('sample root page'), "/", 1)
n2 = NavigationNode(_('sample settings page'), "/bye/", 2)
n3 = NavigationNode(_('sample account page'), "/hello/", 3)
n4 = NavigationNode(_('sample my profile page'), "/hello/world/", 4, 3)
nodes.append(n)
nodes.append(n2)
nodes.append(n3)
nodes.append(n4)
return nodes
menu_pool.register_menu(TestMenu)
Теперь вы можете связать это меню со страницей на вкладке Дополнительно в настройках страницы под прикрепленным меню.
Модификаторы навигации¶
Модификаторы навигации предоставляют вашему приложению доступ к меню навигации.
Модификатор может изменять свойства существующих узлов или перестраивать целые меню.
Примеры использования¶
Простой пример: у вас есть новостное приложение, которое публикует страницы независимо от django CMS. Однако вы хотели бы интегрировать это приложение в структуру меню вашего сайта, чтобы в соответствующих местах в навигационном меню появлялся узел News.
В другом примере, вы можете захотеть, чтобы определенный атрибут вашего Pages
был доступен в шаблонах меню. Для того чтобы узлы меню были легкими (что может быть важно для сайта с тысячами страниц), они содержат только минимальные атрибуты, необходимые для создания удобного меню.
В обоих случаях решением является модификатор навигации - в первом случае для добавления нового узла в соответствующем месте, а во втором - для добавления нового атрибута - на атрибут attr
, а не непосредственно на NavigationNode
, чтобы избежать конфликтов - ко всем узлам в меню.
Как это работает¶
Поместите ваши модификаторы в cms_menus.py
вашего приложения.
Чтобы сделать модификатор доступным, его нужно зарегистрировать с помощью menus.menu_pool.menu_pool
.
Теперь, когда загружается страница и генерируется меню, ваш модификатор сможет осматривать и изменять его узлы.
Вот пример простого модификатора, который помещает атрибут changed_by
каждой страницы в соответствующий атрибут NavigationNode
:
from menus.base import Modifier
from menus.menu_pool import menu_pool
from cms.models import Page
class MyExampleModifier(Modifier):
"""
This modifier makes the changed_by attribute of a page
accessible for the menu system.
"""
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
# only do something when the menu has already been cut
if post_cut:
# only consider nodes that refer to cms pages
# and put them in a dict for efficient access
page_nodes = {n.id: n for n in nodes if n.attr["is_page"]}
# retrieve the attributes of interest from the relevant pages
pages = Page.objects.filter(id__in=page_nodes.keys()).values('id', 'changed_by')
# loop over all relevant pages
for page in pages:
# take the node referring to the page
node = page_nodes[page['id']]
# put the changed_by attribute on the node
node.attr["changed_by"] = page['changed_by']
return nodes
menu_pool.register_modifier(MyExampleModifier)
У него есть метод modify()
, который должен возвращать список экземпляров NavigationNode
. modify()
должен принимать следующие аргументы:
request
Экземпляр запроса Django. Вы хотите модифицировать на основе сессий, пользователя или разрешений?
nodes
Все узлы. Обычно вы хотите вернуть их снова.
namespace
Пространство имен меню. Дается только в том случае, если кто-то запросил меню, содержащее только узлы из этого пространства имен.
root_id
Был ли запрос меню основан на удостоверении личности?
post_cut
Каждый модификатор вызывается два раза. Сначала для всего дерева. После этого дерево обрезается, чтобы показать только те узлы, которые отображаются в текущем меню. После обрезания модификаторы вызываются снова с конечным деревом. В этом случае
post_cut
становитсяTrue
.breadcrumb
Это вызов хлебных крошек, а не вызов меню?
Вот пример встроенного модификатора, который отмечает все уровни узла:
class Level(Modifier):
"""
marks all node levels
"""
post_cut = True
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
if breadcrumb:
return nodes
for node in nodes:
if not node.parent:
if post_cut:
node.menu_level = 0
else:
node.level = 0
self.mark_levels(node, post_cut)
return nodes
def mark_levels(self, node, post_cut):
for child in node.children:
if post_cut:
child.menu_level = node.menu_level + 1
else:
child.level = node.level + 1
self.mark_levels(child, post_cut)
menu_pool.register_modifier(Level)
Проблемы с производительностью в модификаторах меню¶
Навигационные модификаторы могут быстро стать узким местом в производительности. Каждый модификатор вызывается несколько раз: Для хлебной крошки (breadcrumb=True
), для всего дерева меню (post_cut=False
), для дерева меню, урезанного до видимой части (post_cut=True
) и, возможно, для каждого уровня навигации. Выполнение неэффективных операций внутри модификатора навигации может привести к большим проблемам с производительностью. Некоторые советы по поддержанию быстродействия реализации модификатора:
Укажите, когда именно необходим модификатор (в хлебной крошке, до или после разреза).
Рассматривайте только узлы и страницы, имеющие отношение к модификации.
Выполняйте как можно меньше запросов к базе данных (т.е. не в цикле).
В запросах к базе данных получайте именно те атрибуты, которые вас интересуют.
Если вам предстоит выполнить несколько модификаций, старайтесь применять их одним и тем же методом.
Django CMS 3.9
Содержание
- Учебники
- Руководства по эксплуатации
- Установка
- Использование основной функциональности
- Создание новой функциональности
- Вклад
- Справочник
- Основные темы
- Вклад
- Примечания к выпуску и информация об обновлении
- Использование django CMS
Дополнительно
Вы здесь:
-
Документация Django Django CMS 3.9
- Руководства по эксплуатации
- Как настроить меню навигации
- Руководства по эксплуатации