Welcome to django-fiber’s documentation

This is the documentation project for django-fiber.



Usage instructions

Page tree

Fiber was designed to coexist with your existing Django apps. In addition to the URLs that you define in your urls.py files you can create a tree of URLs that Fiber uses to create menus. Each node of the tree is a Page, which:

  • has a title
  • lives at a specific URL
  • references a template
  • serve as a placeholder for Content items
  • can optionally redirect to another URL
  • has some more tricks up its sleeve we’ll talk about later

So before you can use Fiber template tags in your templates, you first have to create the Page tree. A simple Page tree might look like this:

  • mainmenu
    • Home
    • About us
      • Mission
      • Our people
    • News

The root node is a special Page, whose sole purpose is to group Pages into a menu. The title of the root node is used to reference the menu when writing out the menu in your templates. The other properties of the root node (like URL) are ignored by Fiber.

Note: You can create multiple root nodes to create multiple, independent menus.


The URL of a Page can be specified in 3 different ways:

  • as an absolute URL, like this: /this/is/an/absolute-url/
  • as a relative URL, like this: relative-url
  • as a named URL, like this: “news_item_list”
Absolute URLs

Using absolute URLs, you can specify the full URL path to the Page. Absolute URLs should start (and preferably also end) with a slash. You can also specify links to external sites by providing the full URL (starting with http:// or https://).

Relative URLs

Relative URLs are like folders on your computer. The full absolute URL of the Page is determined by walking up the tree, while concatenating relative URLs until the root node is reached, or until an absolute URL is encountered. Relative URLs should not contain slashes.

Named URLs

Named URLs are looked up in the urls.py files of all registered apps. Currently only named URLs that don’t have parameters are supported.


When you have created your Page tree, you can start using the Fiber template tags in your templates. At the beginning of your template(s), load the Fiber template tags:

{% load fiber_tags %}

Using the Fiber template tags, you can:

  • write out content items, that either
    • have a specified name
    • are linked to a specific location on the current page
    • are linked to a specific location on another page
  • write out valid XHTML menu structures
    • of pages below a named root page (this is the menu name),
    • limited to a minimum and maximum level (depth),
    • that mark the currently active page,
    • optionally expanding all descendants of the currently active page,
    • with all possible css hooks you could ever need

Content items

You can write out content items with the ‘show_content’ and ‘show_page_content’ template tags:

{% show_content "content_item_name" %}
{% show_page_content "block_name" %}
{% show_page_content other_page "block_name" %} other_page being a Page object

This shows content item named ‘address’:

{% show_content "address" %}

This shows content items that are linked to the location named ‘content’ on the current page:

{% show_page_content "content" %}

This shows content items that are linked to the location named ‘content’ on another page ‘other_page’:

{% show_page_content other_page "content" %}

Advanced usage

This document is used to gather more advanced usage examples.

Optional settings

These settings are optional (default values are shown):




FIBER_IMAGES_DIR = 'uploads/images'
FIBER_FILES_DIR = 'uploads/files'

FIBER_EDITOR = 'fiber.editor_definitions.ckeditor.EDITOR'

FIBER_PAGE_MANAGER = 'fiber.managers.PageManager'
FIBER_CONTENT_ITEM_MANAGER = 'fiber.managers.ContentItemManager'



COMPRESS = [the opposite of DEBUG]

API_RENDER_HTML = False  # If set to True, you must include 'djangorestframework' in INSTALLED_APPS as well

FIBER_IMAGE_PREVIEW = True  # If set to False, you don't need 'easy_thumbnails' in INSTALLED_APPS
FIBER_LIST_THUMBNAIL_OPTIONS = {'size': (111, 111)}

Set or override fiber_page in a view

In this example, the news_item_detail view looks up the Page of the news_item_list by looking up its named URL. This way, you can reuse the content you have placed on the news_item_list Page for each news_item_detail Page.

def news_item_detail(request, news_item_slug):
    news_item = get_object_or_404(NewsItem, slug=news_item_slug)

    fiber_page = Page.objects.get(url__exact='"news_item_list"')

    t = loader.get_template('news_item_detail.html')
    c = RequestContext(request, {
        'fiber_page': fiber_page,
        'news_item': news_item
    return HttpResponse(t.render(c))

Set or override fiber_page in a class based view

In this example, the NewsItemDetailView’s context is enriched with fiber_page and fiber_current_pages.

from django.core.urlresolvers import reverse
from django.views.generic import DetailView
from fiber.views import FiberPageMixin

class NewsItemDetailView(FiberPageMixin, DetailView):

    def get_fiber_page_url(self):
        return reverse('news_item_list')


In this example 4 page-templates will be available in the front- and backend-admin:

    ('', 'Default template'),
    ('tpl-home.html', 'Home template'),
    ('tpl-intro.html', 'Intro template'),
    ('tpl-with-sidebar.html', 'With sidebar template'),

The first choice ‘’ will load the FIBER_DEFAULT_TEMPLATE, default this is ‘base.html’

In this example 2 content-templates will be available in the front- and backend-admin:

    ('', 'Default template'),
    ('special-content-template.html', 'Special template'),

The first choice ‘’ will load the default content-template, this is ‘fiber/content_item.html’


In this example metadata (key-value pairs) for pages will be available in the backend-admin:

    'title': {
        'widget': 'select',
        'values': ['option1', 'option2', 'option3',],
    'bgcolor': {
        'widget': 'combobox',
        'values': ['#ffffff', '#fff000', '#ff00cc'],
        'prefill_from_db': True,
    'description': {
        'widget': 'textarea',

The first key key is ‘title’. Because it has widget ‘select’ you will have 3 fixed values to choose from.

The second key is ‘bgcolor’. Because it has widget ‘combobox’ you will have 3 fixed values to choose from and the choice to add your own ‘bgcolor’. By setting prefill_from_db to True, the custom values you have chosen will also appear in the selectbox of fixed values.

The third key is ‘description’. Because it has widget ‘textarea’ you can enter the value in a big textarea field.

Available widgets are:
select combobox textarea textfield (default widget)

Only the combobox can prefill from the database by setting prefill_from_db = True (default=False)

The same metadata schema is available for metadata for content:


CKEditor config settings

Some default CKEditor config settings can be altered by creating a file called admin-extra.js, which should be placed in a folder structure like this:


Make sure ‘appname’ is placed _before_ ‘fiber’ in settings.INSTALLED_APPS, otherwise the admin-extra.js file won’t override the default admin-extra.js provided by Django Fiber.

The following config settings can be used in admin-extra.js to override default CKEditor behavior:

window.CKEDITOR_CONFIG_FORMAT_TAGS = 'p;h1;h2;h3;h4';
    { name: 'intro paragraph', element: 'p', attributes: { 'class': 'intro' } }
window.CKEDITOR_CONFIG_EXTRA_PLUGINS = 'fpagelink,ffilelink,fimagelink,fcustomlink,funlink,fimage,table,tabletools';
window.CKEDITOR_CONFIG_REMOVE_PLUGINS = 'scayt,language,menubutton,forms,image,link';
window.CKEDITOR_CONFIG_EXTRA_ALLOWED_CONTENT = 'a[*]{*}(*);img[*]{*}(*);iframe[*];object[*];param[*];embed[*]';

You can also override the entire CKEditor toolbar, by setting the variable:


To see how this works, check the fiber.ckeditor.js file in the Django Fiber source: https://github.com/ridethepony/django-fiber/blob/master/fiber/static/fiber/js/fiber.ckeditor.js

Custom permissions

Fiber provides a fiber.permissions module. The Permission class defined here can be overridden by writing a custom permission class and pointing PERMISSION_CLASS in your settings module to that class.

Here’s an example module that implements object level permissions:

    >>> from django.contrib.auth.models import User
    >>> u = User.objects.get(username='example-user')
    >>> from guardian.shortcuts import assign
    >>> from fiber.models import Page
    >>> p = Page.objects.get(title='A')
    >>> assign('change_page', u, p)

from django.contrib.auth.models import User
from django.db.models import Q
from django.contrib.contenttypes.models import ContentType
from django.db.models.signals import pre_delete

from guardian.shortcuts import get_objects_for_user, get_perms, assign
from guardian.models import UserObjectPermission

from fiber.permissions import Permissions
from fiber.models import Image, File, Page, PageContentItem, ContentItem

PAGE_PERMISSIONS = ('change_page', 'delete_page')
CONTENTITEM_PERMISSIONS = ('change_contentitem', 'delete_contentitem')

def remove_obj_perms_connected_with_object(sender, instance, **kwargs):
    filters = Q(content_type=ContentType.objects.get_for_model(instance),

class CustomPermissions(Permissions):

    def __init__(self):
        Since guardian does not delete permission-objects, when the objects that
        they point to are deleted, we must take care of deleting them our selves.
        See http://packages.python.org/django-guardian/userguide/caveats.html?highlight=caveat
        pre_delete.connect(remove_obj_perms_connected_with_object, sender=Image)
        pre_delete.connect(remove_obj_perms_connected_with_object, sender=File)
        pre_delete.connect(remove_obj_perms_connected_with_object, sender=Page)
        pre_delete.connect(remove_obj_perms_connected_with_object, sender=PageContentItem)
        pre_delete.connect(remove_obj_perms_connected_with_object, sender=ContentItem)

    def filter_objects(self, user, qs):
        Returns all objects that `user` is allowed to change, based on guardian permissions.
        Returns all objects if user is superuser.
        if user.is_superuser:
            return qs
        return qs.filter(id__in=get_objects_for_user(user, 'change_%s' % qs.model.__name__.lower(), qs.model))

    def can_edit(self, user, obj):
        Returns True if `user` is allowed to edit `obj` based on guardian permissions.
        return 'change_%s' % obj.__class__.__name__.lower() in get_perms(user, obj)

    def can_move_page(self, user, page):
        A user with change-permissions is allowed to move the page.
        A superuser always has all permissions as far as guardian is concerned.
        return 'change_page' in get_perms(user, page)

    def object_created(self, user, obj):
        Create 'change' permission to `obj` for `user`.
        assign('change_%s' % obj.__class__.__name__.lower(), user, obj)

    def _filter_user_and_superuser(self, user, qs):
        A user should see files and images owned by him and by the superuser.
        Files uploaded by other non-superusers should not be listed.

        Note - there should be only one superuser in the User model.
        superuser = User.objects.get(is_superuser=True)

        qs = qs.filter(Q(id__in=get_objects_for_user(user, 'change_%s' % qs.model.__name__.lower(), qs.model)) |
            Q(id__in=get_objects_for_user(superuser, 'change_%s' % qs.model.__name__.lower(), qs.model)))
        return qs

    def filter_images(self, user, qs):
        return self._filter_user_and_superuser(user, qs)

    def filter_files(self, user, qs):
        return self._filter_user_and_superuser(user, qs)


The Sitemaps protocol allows a webmaster to inform search engines about URLs on a website that are available for crawling. Django comes with a high-level framework that makes generating sitemap XML files easy.

Install the sitemap application as per the instructions in the django documentation, then edit your project’s urls.py and add a reference to Fiber’s Sitemap class in order to included all the publicly-viewable Fiber pages:

from fiber.sitemaps import FiberSitemap
(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'fiber': FiberSitemap,
                                                              ... other sitemaps... })

Django 1.7 migrations

Django-fiber 1.0 supports Django 1.7. This means that it also uses the new Django 1.7 migrations.

  • The South migrations are removed. If you want to use the old South migrations, then read below.
  • There are no database changes between the previous version (0.13) and 1.0.

Migration from Django-fiber 0.13

  • You want to migrate from Django-fiber 0.13 to 1.0
  • You want to use Django 1.7

Good news! Your database is up-to-date. There are no new migrations.

You still should fake the new migrations. Also see upgrading from south.

python manage.py migrate --fake fiber

Migration from Django-fiber <= 0.12.2

  • You want to to migrate from Django-fiber <= 0.12.2 to 1.0
  • You want to use Django 1.7

You should first upgrade to Django-fiber 0.13:

pip install -U django-fiber==0.13

Do not yet update to Django 1.7.

Apply the migrations:

python manage.py migrate fiber

You can now upgrade to Django-fiber 1.0 and Django 1.7.

Other variations

If you want to keep using Django <= 1.6:

  • You want to migrate from Django-fiber 0.13 to 1.0.

You don’t have to do anything because your database is up-to-date.

  • You migrate from Django-fiber <= 0.12.2 to 1.0.

You should first upgrade to Django-fiber 0.13 and apply the South migrations.


Bart Heesink <bheesink@leukeleu.nl>
Bram Simons <bsimons@leukeleu.nl>
Chi Shang Cheng <cscheng@leukeleu.nl>
Chris Clark <chris@untrod.com>
David Filipovic <david.filipovic@gmail.com>
Dennis Bunskoek <dbunskoek@leukeleu.nl>
Diederik van der Boor <vdboor@edoburu.nl>
Douwe van der Meij <vandermeij@gw20e.com>
Dzjon Hessing <dhessing@ridethepony.nl>
Jaap Roes <jroes@leukeleu.nl>
Jaco Bovenschen <jbovenschen@leukeleu.nl>
Luke Plant <L.Plant.98@cantab.net>
Maarten Draijer <maarten@madra.nl>
Marco Braak <mbraak@ridethepony.nl>
Marko Tibold <mtibold@leukeleu.nl>
Michael van de Waeter <mvandewaeter@leukeleu.nl>
Nick Badoux <nbadoux@leukeleu.nl>
Niels van Dijk <nvandijk@leukeleu.nl>
Ramon de Jezus <rdejezus@leukeleu.nl>
Richard Barran
Selwin Ong <selwin@ui.co.id>
Zenobius Jiricek <zenobius.jiricek@gmail.com>


Custom permissions

fiber.app_settings.DETAIL_THUMBNAIL_OPTIONS = {'size': (228, 228)}

Point this class to your own Permission Class as declared in fiber.permissions.



Module that provides a base Permission class. This class may be overridden by changing the PERMISSION_CLASS value in the settings module.

class fiber.permissions.Permissions[source]

This class defines the methods that a Permission class should implement.

By default all permissions are granted to a staff user.

can_edit(user, obj)[source]

Should return True if user is allowed to edit obj.

can_move_page(user, page)[source]

Should return True if user is allowed to move page.

filter_files(user, qs)[source]

Called by API while listing files.

filter_images(user, qs)[source]

Called by API while listing images.

filter_objects(user, qs)[source]

Should only return those objects whose user is allowed to edit. qs can consist of type Page or ContentItem.


Determines if the user is allowd to see the Fiber admin interface.

object_created(user, obj)[source]

Called whenever a new instance has been created of one of Fiber’s models by user.

Indices and tables