Django Permissions and Groups

Often I need to control access to my views. The built-in Django Permissions and Groups models are designed precisely for this. The problem is the docs are sparse. These notes fill in the details.

The best way to get an idea of how this all works is to use the built-in Django admin to create users and groups. As you can see in admin, Django automatically adds “add”, “change” and “delete” permissions to each model. You can create custom permissions too, but I will not go in to that. You can control access for an individual user or you can create a group, set the group permissions and then add a user to that group. For my projects, I usually think of users in terms of groups, so I use groups to control access instead of controlling access by individual users. One advantage of that is it is easy to alter permissions for many users just by changing group permissions.

Protecting a View with Permissions

By default users cannot create or change a model. Great. My model is safe??? Not so fast. Django permissions do not actually protect anything. Permissions are merely records of the control you want. You need to write the code to check permissions and decide what to do. One easy way to do this is to use the 3rd party Django braces app.

Using Django Braces

When using braces there are a few things to keep in mind. Make sure to read the first few paragraphs at the top of the Access Mixins section. Especially take note of the raise_exception attribute. If this is False and permission is denied, you will get redirected to the login page. But on my website, if the user is already logged in they get passed to the page they were trying to access, creating an infinite loop. Setting raise_exception = True, you get a HTTP 403, which is what I wanted.

Next, as the docs point out, it does not make sense to check permissions if a user is not logged in. One way to ensure that is to use the braces LoginRequiredMixin.

To specify which permission to require, you set the class attribute “permission_required” for your view. But how do you know what string to assign to permission_required? For that, fire up your database browser. First look at the “django_content_type” table. Look for that app_label and model name you want to use permissions for. Write down the app_label and id number for that row. In my case, I wanted to protect the Django User model, so I selected the row with app_label=”auth” and the id in my case was 3. Next go to the “auth_permission” table and look for the content type id. The “code_name” column gives you what you need. Note: with the PostgreSQL admin tool, underscores in strings look like spaces. For the django user model, you will end up with something like this:

permission_required = "auth.change_user"

Setting Permissions Programatically

In many cases you will want to set permissions in your code (i.e. not using the admin tool). The trick to doing that is getting the permission object. For that you need to access ContentType and auth.models.Permission. Like this:

from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType

# Get the app_label and model by inspecting the table django_content_type
user_content_type = ContentType.objects.get(app_label='auth', model='user')

# Get codename by inspecting the table auth_permission
create_user_perm = Permission.objects.get(content_type=user_content_type, codename='add_user')

# To add permission to a user
my_user = User.objects.get(username='my_username')
my_user.permissions.add(create_user_perm)

# To add the permission to a group
my_group = Group.objects.get(name='my_group_name')
my_group.permissions.add(create_user_perm)

# To add user to group
my_user.groups.add(my_group)

That’s all for now.