Understanding Permissions and Groups in Django

Django’s authentication and authorization system is one of its strongest features. It provides a complete framework for managing users, authentication, and permissions, giving developers full control over what each user can do within an application. One of the key parts of this system is the permission-based access control, along with groups that allow you to organize and manage permissions more efficiently.

In this post, we’ll go deep into how Django’s permissions work, how you can define custom permissions, how to use groups to manage roles, and how to check permissions in both views and templates. We will also explore how you can extend this system to create role-based access control (RBAC) for real-world applications.

Table of Contents

  1. Introduction to Django’s Permission System
  2. The Default Permissions in Django
  3. Assigning Permissions to Users
  4. Creating and Managing Custom Permissions
  5. Using Groups to Bundle Permissions
  6. Assigning Groups to Users
  7. Checking Permissions in Views
  8. Checking Permissions in Templates
  9. Using the User and Group Models
  10. Working with Django Admin Permissions
  11. Implementing Role-Based Access Control (RBAC)
  12. Practical Example: Building a Blog with Editors and Authors
  13. Managing Permissions Programmatically
  14. Extending Django’s Default Permission System
  15. Best Practices for Permissions and Groups
  16. Common Pitfalls and How to Avoid Them
  17. Conclusion

1. Introduction to Django’s Permission System

In most web applications, not every user should have the same level of access. For instance, in a blogging platform, you might have authors who can create and edit their own posts, editors who can review and approve articles, and administrators who can manage everything.

Django’s permission system helps implement this kind of access control easily. Every user can be assigned permissions that determine what actions they can perform. Permissions can be attached directly to users or through groups.

Django’s permission system works hand in hand with its authentication framework (django.contrib.auth). This framework provides models and utilities for managing users, groups, and permissions.


2. The Default Permissions in Django

When you create a Django model, Django automatically creates three permissions for it:

  • add_<modelname> – allows the user to add instances of the model.
  • change_<modelname> – allows the user to modify instances of the model.
  • delete_<modelname> – allows the user to delete instances of the model.

If you have a model named Article inside an app called blog, Django automatically creates:

  • blog.add_article
  • blog.change_article
  • blog.delete_article

You can check these permissions in the database under the auth_permission table. This table stores all permission codes and their corresponding names.

You can also create custom permissions if the default three are not enough — for example, publish_article.


3. Assigning Permissions to Users

Each user in Django has a field called user_permissions, which is a many-to-many relationship with the Permission model. You can assign permissions directly to users in several ways.

Example 1: Assign Permissions in the Admin

In the Django admin interface, open the user’s page and scroll to the “User permissions” section. From there, you can select which permissions to assign.

Example 2: Assign Permissions in Code

You can also assign permissions programmatically using Django’s ORM.

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

# Get the permission
content_type = ContentType.objects.get_for_model(Article)
permission = Permission.objects.get(
codename='change_article',
content_type=content_type,
) # Get the user user = User.objects.get(username='john') # Add permission to the user user.user_permissions.add(permission)

Now, the user john has permission to change articles.


4. Creating and Managing Custom Permissions

Default permissions cover basic CRUD operations, but many applications require more specific permissions.

You can define custom permissions in your model’s Meta class.

class Article(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
    permissions = &#91;
        ("publish_article", "Can publish article"),
        ("view_unpublished_article", "Can view unpublished article"),
    ]

After defining custom permissions, run python manage.py makemigrations and python manage.py migrate. Django will create these new permissions in the database.

You can then assign them to users or groups in the same way as default permissions.


5. Using Groups to Bundle Permissions

Managing permissions for many users individually can quickly become complex. That’s where groups come in.

A group is a collection of permissions. When you assign a group to a user, the user automatically gains all permissions that belong to that group.

This is extremely useful for defining roles like Admin, Editor, or Author. Instead of assigning ten permissions to each editor, you just assign them to a group called “Editor” and then add users to that group.


6. Assigning Groups to Users

You can create and assign groups either in the Django admin or programmatically.

In the Admin

  • Go to the “Groups” section in the admin panel.
  • Create a new group (e.g., “Editors”).
  • Add the desired permissions to this group.
  • Then open a user’s page and assign the user to the “Editors” group.

In Code

from django.contrib.auth.models import Group, Permission

# Create a group
editors = Group.objects.create(name='Editors')

# Add permissions to the group
permission = Permission.objects.get(codename='change_article')
editors.permissions.add(permission)

# Add a user to the group
user = User.objects.get(username='alice')
user.groups.add(editors)

Now, the user alice automatically has the change_article permission because she belongs to the Editors group.


7. Checking Permissions in Views

Django provides several ways to check if a user has a certain permission.

Using user.has_perm()

You can check permissions directly using this method.

if request.user.has_perm('blog.change_article'):
# User can change articles
...
else:
# Permission denied
...

Using @permission_required Decorator

You can also use the permission_required decorator to protect views.

from django.contrib.auth.decorators import permission_required

@permission_required('blog.add_article')
def create_article(request):
# Only users with add_article permission can access this view
...

If a user without the required permission tries to access this view, they will be redirected to the login page by default.

You can also set raise_exception=True to raise a PermissionDenied error instead of redirecting.


8. Checking Permissions in Templates

You can check permissions directly in templates using the perms template context variable.

{% if perms.blog.add_article %}
&lt;a href="{% url 'article_add' %}"&gt;Add Article&lt;/a&gt;
{% endif %}

This allows you to show or hide UI elements depending on the user’s permissions.


9. Using the User and Group Models

The main models for managing users and groups are:

  • User – represents individual users.
  • Group – represents roles or permission bundles.
  • Permission – represents specific actions users can perform.

Django’s User model automatically includes relationships to Group and Permission:

  • user.groups – groups the user belongs to.
  • user.user_permissions – permissions assigned directly to the user.

You can access them like this:

user = User.objects.get(username='bob')
user.groups.all()  # List of groups
user.user_permissions.all()  # List of specific permissions

10. Working with Django Admin Permissions

Django admin respects the same permission system.
Users can access specific models or actions in the admin only if they have the correct permissions.

For example:

  • To view a model in admin, the user must have view_modelname permission.
  • To add an object, they must have add_modelname.
  • To change or delete objects, they need change_modelname or delete_modelname.

You can control this at a granular level by assigning or revoking permissions in the admin interface.


11. Implementing Role-Based Access Control (RBAC)

Role-Based Access Control (RBAC) is a pattern where permissions are not assigned directly to users, but through roles (implemented as groups in Django).

For example:

RolePermissions
Adminadd, change, delete any model
Editorchange and publish articles
Authoradd and edit own articles

This structure makes it easy to manage access because you only need to modify the group’s permissions when roles change.


12. Practical Example: Building a Blog with Editors and Authors

Let’s walk through a practical example to demonstrate how permissions and groups can be applied.

Step 1: Define Models and Custom Permissions

class Article(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
published = models.BooleanField(default=False)
class Meta:
    permissions = &#91;
        ('publish_article', 'Can publish article'),
    ]

Step 2: Create Groups

  • Admins: All permissions.
  • Editors: change_article, publish_article.
  • Authors: add_article, change_article.

Step 3: Assign Groups

admin_group = Group.objects.create(name='Admins')
editor_group = Group.objects.create(name='Editors')
author_group = Group.objects.create(name='Authors')

# Assign permissions
admin_group.permissions.set(Permission.objects.all())
editor_group.permissions.set(Permission.objects.filter(codename__in=['change_article', 'publish_article']))
author_group.permissions.set(Permission.objects.filter(codename__in=['add_article', 'change_article']))

Step 4: Restrict Views Based on Permissions

from django.contrib.auth.decorators import permission_required

@permission_required('blog.publish_article')
def publish_article(request, pk):
...

This ensures only editors or admins can publish articles.


13. Managing Permissions Programmatically

You can dynamically create, assign, and revoke permissions using Django’s ORM.

Create a Permission

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from blog.models import Article

content_type = ContentType.objects.get_for_model(Article)
permission = Permission.objects.create(
codename='archive_article',
name='Can archive article',
content_type=content_type,
)

Revoke a Permission

user.user_permissions.remove(permission)

Clear All Permissions from a User

user.user_permissions.clear()

14. Extending Django’s Default Permission System

You can extend Django’s permission system to suit your needs.

Object-Level Permissions

By default, Django permissions apply at the model level. For example, if a user has change_article, they can change any article.
However, sometimes you want to restrict users to only modify their own objects.

For this, you can use third-party packages like django-guardian, which supports object-level permissions.

Example:

from guardian.shortcuts import assign_perm

assign_perm('change_article', user, obj)

Now the permission applies only to that specific object.


15. Best Practices for Permissions and Groups

  1. Use Groups for Roles – Always use groups to manage common permission sets.
  2. Keep Custom Permissions Descriptive – Use clear, consistent names.
  3. Avoid Hardcoding Permissions in Code – Store permission checks in decorators or centralized utilities.
  4. Document Role Responsibilities – Maintain documentation describing what each group can do.
  5. Use the Admin for Simple Permission Management – For small teams, the Django admin is sufficient.
  6. Use Object-Level Permissions When Necessary – For large systems, consider django-guardian or similar tools.
  7. Regularly Audit Permissions – Periodically verify that roles and permissions are aligned with your current requirements.

16. Common Pitfalls and How to Avoid Them

  1. Forgetting to Migrate After Adding Custom Permissions
    Always run migrations after modifying your permissions list in a model’s Meta.
  2. Assigning Permissions to the Wrong App
    Double-check your permission code format: app_label.permission_codename.
  3. Not Checking Permissions in Templates
    Even if you restrict backend access, also hide restricted UI elements using the perms template variable.
  4. Overusing Direct Permissions
    Assigning permissions directly to users leads to clutter. Use groups instead.
  5. Ignoring Object-Level Needs
    If users should only edit their own data, implement object-level checks in views.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *