Nodes are useful for structuring a website; however, they are inherently unsuitable for creating site navigation.

The most glaring problem is that a navigation tree based on Nodes would have one Node as the root, whereas navigation usually has multiple objects at the top level.

Additionally, navigation needs to have display text that is relevant to the current context; however, Nodes do not have a field for that, and View subclasses with a name or title field will generally need to use it for database-searchable names.

Finally, Node structures are inherently unordered, while navigation is inherently ordered.

shipherd exists to resolve these issues by separating navigation structures from Node structures. It is instead structured around the way that site navigation works in the wild:

  • A site may have one or more independent navigation bars (Main navigation, side navigation, etc.)
  • A navigation bar may be shared by sections of the website, or even by the entire site.
  • A navigation bar has a certain depth that it displays to.

The Navigation model supplies these features by attaching itself to a Node via ForeignKey and adding a navigation property to Node which provides access to a Node instance’s inherited Navigations.

Each entry in the navigation bar is then represented by a NavigationItem, which stores information such as the order and text for the entry. Given an HttpRequest, a NavigationItem can also tell whether it is_active() or has_active_descendants().

Since the common pattern is to recurse through a navigation tree and render each part similarly, shipherd also ships with the recursenavigation template tag.


class philo.contrib.shipherd.models.NavigationMapper(node)

Bases: object, UserDict.DictMixin

The NavigationMapper is a dictionary-like object which allows easy fetching of the root items of a navigation for a node according to a key. A NavigationMapper instance will be available on each node instance as Node.navigation if shipherd is in the INSTALLED_APPS

class philo.contrib.shipherd.models.Navigation(*args, **kwargs)

Bases: philo.models.base.Entity

Navigation represents a group of NavigationItems that have an intrinsic relationship in terms of navigating a website. For example, a main navigation versus a side navigation, or a authenticated navigation versus an anonymous navigation.

A Navigation‘s NavigationItems will be accessible from its related Node and that Node‘s descendants through a NavigationMapper instance at Node.navigation. Example:

>>> node.navigation_set.all()
>>> parent = node.parent
>>> items = parent.navigation_set.get(key='main').roots.all()
>>> parent.navigation["main"] == node.navigation["main"] == list(items)

A NavigationManager instance.


The Node which the Navigation is attached to. The Navigation will also be available to all the Node‘s descendants and will override any Navigation with the same key on any of the Node‘s ancestors.


Each Navigation has a key which consists of one or more word characters so that it can easily be accessed in a template as {{ node.navigation.this_key }}.


There is no limit to the depth of a tree of NavigationItems, but depth will limit how much of the tree will be displayed.

class philo.contrib.shipherd.models.NavigationItem(*args, **kwargs)

Bases: philo.models.base.TreeEntity, philo.models.nodes.TargetURLModel

NavigationItem(id, parent_id, lft, rght, tree_id, level, target_node_id, url_or_subpath, reversing_parameters_json, navigation_id, text, order)


A ForeignKey to a Navigation instance. If this is not null, then the NavigationItem will be a root node of the Navigation instance.


The text which will be displayed in the navigation. This is a CharField instance with max length 50.


The order in which the NavigationItem will be displayed.


Returns True if the NavigationItem is considered active for a given request and False otherwise.


Returns True if the NavigationItem has active descendants and False otherwise.

class philo.contrib.shipherd.models.NavigationManager

Template tags

templatetag shipherd.recursenavigation

The recursenavigation templatetag takes two arguments:

It will then recursively loop over each NavigationItem in the Navigation and render the template chunk within the block. recursenavigation sets the following variables in the context:

Variable Description
navloop.depth The current depth of the loop (1 is the top level)
navloop.depth0 The current depth of the loop (0 is the top level)
navloop.counter The current iteration of the current level(1-indexed)
navloop.counter0 The current iteration of the current level(0-indexed)
navloop.first True if this is the first time through the current level
navloop.last True if this is the last time through the current level
navloop.parentloop This is the loop one level “above” the current one
item The current item in the loop (a NavigationItem instance)
children If accessed, performs the next level of recursion. True if the item is active for this request
navloop.active_descendants True if the item has active descendants for this request


    {% recursenavigation node "main" %}
        <li{% if %} class='active'{% endif %}>
            <a href="{{ item.get_target_url }}">{{ item.text }}</a>
            {% if item.get_children %}
                    {{ children }}
            {% endif %}
    {% endrecursenavigation %}


{% recursenavigation %} requires that the current HttpRequest be present in the context as request. The simplest way to do this is with the request context processor. Simply make sure that django.core.context_processors.request is included in your TEMPLATE_CONTEXT_PROCESSORS setting.

templatefilter shipherd.has_navigation(node, key=None)

Returns True if the node has a Navigation with the given key and False otherwise. If key is None, returns whether the node has any Navigations at all.

templatefilter shipherd.navigation_host(node, key)

Returns the Node which hosts the Navigation which node has inherited for key. Returns node if any exceptions are encountered.

Project Versions

Table Of Contents

Previous topic


Next topic


This Page