django-tabination is a library that enables you to easily build your
own tab navigation templates by extending the
views.TabView base class.
The library is strongly based on the class based views that Django has introduced with version 1.3. You cannot use this library if your project is using function based views.
Creating tab views¶
For a working custom tab view, the following things are requried:
- You need to extend the
- You need to add the class attribute
_is_tab = Trueto your view
- You need to specify the
- Each tab needs a
- In order for the tab to be visible in your navigation, you need to
- You need to define a
_is_tab attribute is needed for the class to be tracked by a
tracking metaclass. Therefore it needs to be present when the
classes are parsed by the Python interpreter and cannot be added
later, e.g. with a decorator.
The base class resides in
tabination.views. Import it like this:
from tabination.views import TabView
This is a very simple example tab:
class SpamTab(TabView): _is_tab = True tab_id = 'spam' tab_group = 'main_navigation' tab_label = 'Spam' template_name = 'tabs/spam_tab.html'
Now your page will be rendered using the template tabs/spam_tab.html,
views.TabView extends Django’s generic TemplateView.
If you want, you can also use other generic view mixins (or any other custom mixins) to provide additional functionality. A good example would be the SingleObjectMixin:
from django.views.generic.detail import SingleObjectMixin class SpamTab(SingleObjectMixin, TabView): _is_tab = True tab_id = 'spam' tab_group = 'main_navigation' tab_label = 'Spam' template_name = 'tabs/spam_tab.html' model = models.SpamCan
Now the SpamCan object with a primary key provided from your URL
definition will be passed on to your template as
As of Django 1.4, above example does not work due to a bug in the
class based views implementation (
get_context_data in the
generic mixins does not call
super()). This is fixed in Django
1.5 (see Ticket #16074). If you’re still using Django 1.4 you can
either use generic mixins that don’t affect
TabView.get_context_data(self, **kwargs) from your
tab code or create your own mixins. See the next section for an
You can do everything with your TabView that you can do with normal
class based views. The only things that you need to bear in mind is that
views.TabView always needs to be the base class (on the right side of the
parentheses). It may be overloaded using mixins but cannot be combined
with other views that override
Customizing your tab view¶
You can further customize your tab view by overloading the
class attributes with your own class- or instance attributes or
properties (if logic is required).
For available attributes, see
views.TabView documentation. You can also
create your own attributes, as long as they’re used in your template.
Keep in mind that if the tab you’re working with is not the currently
loaded tab, it is just an instance of the tab that has not passed
through the dispatching functions. In case you need some variables that
you get only by dispatching the request (e.g.
self.kwargs), you can
use the special attribute
self.current_tab to gain access to the
currently loaded tab. See also section Accessing request data.
Here is an example of a more sophisticated tab view hierarchy:
from django.contrib.auth.decorators import login_required from django.utils import decorators from django.utils.translation import ugettext as _ from tabination.views import TabView class MainNavigationBaseTab(TabView): """Base class for all main navigation tabs.""" tab_group = 'main_navigation' tab_classes = ['main-navigation-tab'] def get_context_data(self, **kwargs): context = super(MainNavigationBaseTab, self).get_context_data(**kwargs) context['spam'] = 'ham' return context @property def tab_classes(self): """If user is logged in, set ``logged_in_only`` class.""" classes = super(MainNavigationBaseTab, self).tab_classes[:] if self.current_tab.request.user.is_authenticated(): classes += ['logged_in_only'] return classes class SpamTab(MainNavigationBaseTab): """A simple TabView.""" _is_tab = True tab_id = 'spam' tab_label = _('Spam') template_name = 'spam_tab.html' class HamTab(MainNavigationBaseTab): """TabView is only visible after authentication.""" _is_tab = True tab_id = 'ham' tab_label = _('Ham') tab_rel = 'nofollow,noindex' template_name = 'ham_tab.html' @decorators.method_decorator(login_required) def dispatch(self, *args, **kwargs): """Make sure only authenticated users can access this tab.""" return super(HamTab, self).dispatch(*args, **kwargs) @property def tab_visible(self): """Show tab only if current user is logged in.""" return self.current_tab.request.user.is_authenticated() class HiddenTab(MainNavigationBaseTab): """A hidden TabView.""" _is_tab = True tab_id = 'hidden' template_name = 'hidden_tab.html'
In this example, a base tab class was created. Because it does not
_is_tab class attribute, it is not listed as a tab
itself (which wouldn’t be possible anyway, as it has no
MainNavigationBaseTab. The base class predefines a
tab group, so each extending tab doesn’t have to define it again,
therefore following the DRY principle. It also adds a new context
spam to the context of each tab.
The second tab,
HamTab, overrides some more attributes. In this
example, the tab is only visible in the template if the current user is
logged in. Additionally, if the user is logged in, a new CSS class
logged_in_only gets added to the
tab_classes list, in order to be
able to show the user that this is a “secret” tab that guest users
aren’t able to see. A copy of the
tab_classes list is used because
otherwise the CSS class would be added to all classes which extend
The third tab,
HiddenTab, doesn’t define a
tab_label and is
therefore not shown at all (see default behavior of
Keep in mind that if you’re overriding
**kwargs), you need to call the superclasses’ versions of the
method first (like in the example above). Otherwise, you’ll override
tabs context variable.
Accessing request data¶
If you want to access
self.request in a function used to render the
tab item in your template, you may notice that it is not available. This
is because the tab instances other than your current tab don’t pass
through the request dispatching functions.
If you need access to your current request information, you can access
it via the
self.current_tab attribute, e.g.:
class SpamTab(TabView): # (...) def username(self): current_tab = self.current_tab user = current_tab.request.user return user.username
Tabs are sorted by their
weight attribute automatically. Tabs with a
lower weight are sorted before tabs with a higher weight. The default
weight is 0. Negative values are also allowed and will be
sorted before postive values. If two tabs have the same weight the
natural order of the classes is used.