In this document we discuss three different way of customising the navigation menus of django CMS sites.
Create a menu.py in your application and write the following inside:
from menus.base import Menu, NavigationNode
from menus.menu_pool import menu_pool
from django.utils.translation import ugettext_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)
If you refresh a page you should now see the menu entries from above. The get_nodes function should return a list of NavigationNode instances. A NavigationNode takes the following arguments:
Additionally, each NavigationNode provides a number of methods which are detailed in the NavigationNode API references.
To adapt your menus according to request dependent conditions (say: anonymous / logged in user), you can use Navigation Modifiers or you can leverage existing ones.
For example it’s possible to add {'visible_for_anonymous': False} / {'visible_for_authenticated': False} attributes recognized by the django CMS core AuthVisibility modifier.
Complete example:
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}),
]
Classes that extend from menus.base.Menu always get attached to the root. But if you want the menu to be attached to a CMS Page you can do that as well.
Instead of extending from Menu you need to extend from cms.menu_bases.CMSAttachMenu and you need to define a name. We will do that with the example from above:
from menus.base import NavigationNode
from menus.menu_pool import menu_pool
from django.utils.translation import ugettext_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)
Now you can link this Menu to a page in the ‘Advanced’ tab of the page settings under attached menu.
Navigation Modifiers give your application access to navigation menus.
A modifier can change the properties of existing nodes or rearrange entire menus.
A simple example: you have a news application that publishes pages independently of django CMS. However, you would like to integrate the application into the menu structure of your site, so that at appropriate places a News node appears in the navigation menu.
In such a case, a Navigation Modifier is the solution.
Normally, you’d want to place modifiers in your application’s menu.py.
To make your modifier available, it then needs to be registered with menus.menu_pool.menu_pool.
Now, when a page is loaded and the menu generated, your modifier will be able to inspect and modify its nodes.
A simple modifier looks something like this:
from menus.base import Modifier
from menus.menu_pool import menu_pool
class MyMode(Modifier):
"""
"""
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
if post_cut:
return nodes
count = 0
for node in nodes:
node.counter = count
count += 1
return nodes
menu_pool.register_modifier(MyMode)
It has a method modify() that should return a list of NavigationNode instances. modify() should take the following arguments:
Here is an example of a built-in modifier that marks all node levels:
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)
Enter search terms or a module, class or function name.