Создайте cms_menus.py в вашем приложении, со следующим:
frommenus.baseimportMenu,NavigationNodefrommenus.menu_poolimportmenu_poolfromdjango.utils.translationimportgettext_lazyas_classTestMenu(Menu):defget_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)returnnodesmenu_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
Словарь дополнительных атрибутов, которые вы можете использовать в модификаторе или в шаблоне
Чтобы адаптировать меню в зависимости от условий запроса (скажем: анонимный/залогиненный пользователь), вы можете использовать Navigation Modifiers или воспользоваться существующими.
Например, можно добавить атрибуты {'visible_for_anonymous':False}/{'visible_for_authenticated':False}, распознаваемые модификатором AuthVisibility ядра django CMS.
Классы, которые расширяются из menus.base.Menu, всегда прикрепляются к корню. Но если вы хотите, чтобы меню было прикреплено к странице CMS, вы можете сделать и это.
Простой пример: у вас есть новостное приложение, которое публикует страницы независимо от django CMS. Однако вы хотели бы интегрировать это приложение в структуру меню вашего сайта, чтобы в соответствующих местах в навигационном меню появлялся узел News.
В другом примере, вы можете захотеть, чтобы определенный атрибут вашего Pages был доступен в шаблонах меню. Для того чтобы узлы меню были легкими (что может быть важно для сайта с тысячами страниц), они содержат только минимальные атрибуты, необходимые для создания удобного меню.
В обоих случаях решением является модификатор навигации - в первом случае для добавления нового узла в соответствующем месте, а во втором - для добавления нового атрибута - на атрибут attr, а не непосредственно на NavigationNode, чтобы избежать конфликтов - ко всем узлам в меню.
Поместите ваши модификаторы в cms_menus.py вашего приложения.
Чтобы сделать модификатор доступным, его нужно зарегистрировать с помощью menus.menu_pool.menu_pool.
Теперь, когда загружается страница и генерируется меню, ваш модификатор сможет осматривать и изменять его узлы.
Вот пример простого модификатора, который помещает атрибут changed_by каждой страницы в соответствующий атрибут NavigationNode:
frommenus.baseimportModifierfrommenus.menu_poolimportmenu_poolfromcms.modelsimportPageclassMyExampleModifier(Modifier):""" This modifier makes the changed_by attribute of a page accessible for the menu system. """defmodify(self,request,nodes,namespace,root_id,post_cut,breadcrumb):# only do something when the menu has already been cutifpost_cut:# only consider nodes that refer to cms pages# and put them in a dict for efficient accesspage_nodes={n.id:nforninnodesifn.attr["is_page"]}# retrieve the attributes of interest from the relevant pagespages=Page.objects.filter(id__in=page_nodes.keys()).values('id','changed_by')# loop over all relevant pagesforpageinpages:# take the node referring to the pagenode=page_nodes[page['id']]# put the changed_by attribute on the nodenode.attr["changed_by"]=page['changed_by']returnnodesmenu_pool.register_modifier(MyExampleModifier)
У него есть метод modify(), который должен возвращать список экземпляров NavigationNode. modify() должен принимать следующие аргументы:
request
Экземпляр запроса Django. Вы хотите модифицировать на основе сессий, пользователя или разрешений?
nodes
Все узлы. Обычно вы хотите вернуть их снова.
namespace
Пространство имен меню. Дается только в том случае, если кто-то запросил меню, содержащее только узлы из этого пространства имен.
root_id
Был ли запрос меню основан на удостоверении личности?
post_cut
Каждый модификатор вызывается два раза. Сначала для всего дерева. После этого дерево обрезается, чтобы показать только те узлы, которые отображаются в текущем меню. После обрезания модификаторы вызываются снова с конечным деревом. В этом случае post_cut становится True.
breadcrumb
Это вызов хлебных крошек, а не вызов меню?
Вот пример встроенного модификатора, который отмечает все уровни узла:
classLevel(Modifier):""" marks all node levels """post_cut=Truedefmodify(self,request,nodes,namespace,root_id,post_cut,breadcrumb):ifbreadcrumb:returnnodesfornodeinnodes:ifnotnode.parent:ifpost_cut:node.menu_level=0else:node.level=0self.mark_levels(node,post_cut)returnnodesdefmark_levels(self,node,post_cut):forchildinnode.children:ifpost_cut:child.menu_level=node.menu_level+1else:child.level=node.level+1self.mark_levels(child,post_cut)menu_pool.register_modifier(Level)
Проблемы с производительностью в модификаторах меню¶
Навигационные модификаторы могут быстро стать узким местом в производительности. Каждый модификатор вызывается несколько раз: Для хлебной крошки (breadcrumb=True), для всего дерева меню (post_cut=False), для дерева меню, урезанного до видимой части (post_cut=True) и, возможно, для каждого уровня навигации. Выполнение неэффективных операций внутри модификатора навигации может привести к большим проблемам с производительностью. Некоторые советы по поддержанию быстродействия реализации модификатора:
Укажите, когда именно необходим модификатор (в хлебной крошке, до или после разреза).
Рассматривайте только узлы и страницы, имеющие отношение к модификации.
Выполняйте как можно меньше запросов к базе данных (т.е. не в цикле).
В запросах к базе данных получайте именно те атрибуты, которые вас интересуют.
Если вам предстоит выполнить несколько модификаций, старайтесь применять их одним и тем же методом.