Take the 2-minute tour ×

I'm working on a project and I need to be able to programatically inject a number of application-model-based items into an existing CMS-based menu. I've started to use the code found here to modify the menu: http://docs.django-cms.org/en/2.3.3/extending_cms/app_integration.html.

EDIT: Much more detail

My client would like me to attach application-model objects to the CMS menu so that they are children of an existing CMS page in the menu. I currently have a total hack in place which requires me to make fake pages in the CMS that are children of the desired menu item, have the same name as the application-model objects, then, I've installed a Modifier like so:

class SportsMenuModifier(Modifier):
  def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
    if post_cut:
      return nodes

    for node in nodes:
      if node.title == "Baseball":
        node.url = "/sports/baseball"
      elif node.title == "Football":
        node.url = "/sports/Football"
      elif node.title == "Bowling":
        node.url = "/sports/bowling"
      elif node.title == "Golf":
        node.url = "/sports/golf"

    return nodes


There is so much wrong with this I don't know where to begin, but I'll use this non-exhaustive list to highlight some of the most basic issues:

  • Requires the presence of "Fake" CMS pages
  • Ridiculously dependent on the naming of the application sports objects and the fake pages
  • Will not detect when the customer creates new sports objects
  • Very confusing for everyone involved

What I was hoping I could do was something like this (WILL NOT WORK):

in models.py

from django.db import models
from cms.models.pagemodel import Page

class Sport(models.Model):
  name = models.CharField(...)
  parent = modes.ForeignKey(Page, ...)

in menu.py

class SportsMenu(Menu):
  def get_nodes(self, request):
    nodes = []

    for sport in Sports.objects.filter(...).order_by('order'):
      node = NavigationNode(

    return nodes


I'm not sure I can continue with this approach because:

  1. I don't know how to fetch the menu.namespace for a given Page

  2. Even when I hard-code the namespace to "CMSMenu" (I read somewhere this is what it is), this still does nothing that I can see.

So, how do we attach application-model based objects as children to existing CMS-page-based menu items?

share|improve this question
Have you tried to use AppHooks? Don't forget to execute this part at the end: > Now edit a page and open the advanced settings tab. Select your new apphook under “Application”. Save the page. That way you can insert a custom application-model based menu into page of choice. –  Bula Oct 31 '12 at 18:22

1 Answer 1

up vote 3 down vote accepted

The answer for this is that I should have been using (and AM using) Attach Menus which are, unfortunately, VERY poorly documented here: https://django-cms.readthedocs.org/en/latest/extending_cms/app_integration.html#attach-menus.

Also, while I was following those instructions, I accidentally imported CMSAttachMenu from menus.base rather than from cms.menu_bases which doesn't result in any errors, but also doesn't do anything, so, it was rather difficult to debug =/

Here is some working code in case it helps anyone in the future:

in models.py

from django.db import models

class Sport(models.Model):
  name = models.CharField(max_length=64, blank=True)
  slug = models.SlugField(blank=True)

  def __unicode__(self):
    return self.name

  def get_absolute_url(self):
    return "/sports/" + self.slug

In menu.py

from cms.menu_bases import CMSAttachMenu
from django.utils.translation import ugettext_lazy as _
from menus.base import NavigationNode
from menus.menu_pool import menu_pool

from apps.theproject.models import Sport

class SportSubMenu(CMSAttachMenu):

  name = _("Sports Sub-Menu")

  def get_nodes(self, request):

    nodes = []
    for sport in Sport.objects.order_by('order'):
      node = NavigationNode(

    return nodes


Once these two files are in-place, restart the service. In Django-CMS, navigate to the page whose menu-item you'd like to have the various Sports object appear as children menu-items in your menu.

In the Advanced Settings section (which is normally collapsed), you'll see a new option "Attached Menu", choose the new item "Sports Sub-Menu" and you'll be in business.

share|improve this answer
Great help! Would be nice to have such an example in the documentation... –  bhell Mar 29 '13 at 13:28
+1 for figuring out you should never use hardcoded urls in your code. It would have been even nicer if you could've used reversed urls in your model: def get_absolute_url(self): return reverse('sportview', args=[self.slug]) –  Hussam Aug 7 '13 at 19:22

Your Answer


