Views

Note

The code described here is in example/exampleapp/views.py.

View mixins

Most of the views in the example application are pretty straightforward, so we’ll concentrate on the oddities and differences here. All of the views use Django’s class-based views: local classes are defined deriving from things like django.views.generic.ListView including some mixins to add extra functionality:

UserMixin
Because we’re interested in demonstrating permissions for different users, we want to make it easy to switch back and forth between different user accounts to look at what actions are possible for different users in different views. To do this, we use a custom authentication backend (defined in example/exampleapp/views.py) that bypasses authentication checking, we add UserMixin to all of our view classes to include a list of all available users in the view context data, and we include a menu to select the current user at the bottom of every view (it’s set up in the base template for the application).
PermissionInfoMixin
This mixin just adds a list of available actions to the view context data, based on the current user and the object or objects rendered in the view. (Where there’s more than one object in the view, actions are parenthesised if they’re only available for a subset of the displayed objects.) This action list is rendered in the base template, just like the user selection menu.
PermissionRequiredMixin
This is the main django-tutelary mixin for handling permissions for views, except that we catch permission errors and display them as Django messages (well, just a big red “PERMISSION DENIED” message, but it’s a proof of concept…). There is one small wrinkle here, required because of the user switching menu we have. It’s possible to be looking at a view that’s permitted for the current user, then to switch to a user for whom that view isn’t permitted. When that happens, we get into a redirect loop because we can’t redisplay the referring view – instead, we just drop out to the index page.

Using these mixins, defining a typical view class looks something like:

import django.views.generic as generic
from django.contrib.auth.models import User
import tutelary.mixins as mixins

...

class UserMixin:
    ...

class PermissionInfoMixin:
    ...

class PermissionRequiredMixin(mixins.PermissionRequiredMixin):
    ...

...

class ListView(UserMixin, PermissionInfoMixin,
               PermissionRequiredMixin,
               generic.ListView):
    pass

...

class UserList(ListView):
    model = User
    permission_required = 'user.list'

User forms

The only views that have any level of complexity are the user forms. That’s because they allow you to control the assignment of policies to a user, and that means a little bit of Django form gymnastics to get everything working. Little of that complexity is associated with using django-tutelary, but it does show how easy it is to do more complex view management without django-tutelary getting in the way.