Open In App

User Groups with Custom Permissions in Django - Python

Last Updated : 24 May, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Our task is to design the backend efficiently following the DRY (Don't Repeat Yourself) principle, by grouping users and assigning permissions accordingly. Users inherit the permissions of their groups.

Let's consider a trip booking service, how they work with different plans and packages. There is a list of product which subscriber gets on subscribing to different packages, provided by the company. Generally, the idea they follow is the level-wise distribution of different products.

Let's see the different packages available on tour booking service :

  1. Starter plan : In this package, subscriber will get the facility of non-AC bus travel and 1-day stay in a non-AC room only. Let's say the trip is from Delhi to Haridwar(a religious place in Uttarakhand).
  2. Golden Plan : It will be somewhat costly than the Starter Plan. In this plan, subscriber will be given 2-day stay in a non-AC room, travelling in a AC bus and the trip will be from Delhi to Haridwar, Rishikesh and Mussoorie.
  3. Diamond Plan: This is the most costly plan, in which subscriber will be provided 3-day plan with AC bus and AC room stay, along with the trip to Haridwar, Rishikesh and Mussoorie and also trip to the Water Park.

Define Custom User Model with Permissions

Create a Django app called users. Inside users/models.py:

Python
from django.contrib.auth.models import AbstractUser
from django.utils import timezone
from django.db import models

class User(AbstractUser):

    first_name = models.CharField(_('First Name of User'),
                            blank = True, max_length = 20)
                            
    last_name = models.CharField(_('Last Name of User'),
                            blank = True, max_length = 20)
                            
    class Meta:
        
        permissions = (
            ("can_go_in_non_ac_bus", "To provide non-AC Bus facility"),
            ("can_go_in_ac_bus", "To provide AC-Bus facility"),
            ("can_stay_ac-room", "To provide staying at AC room"),
            ("can_stay_ac-room", "To provide staying at Non-AC room"),
            ("can_go_dehradoon", "Trip to Dehradoon"),
            ("can_go_mussoorie", "Trip to Mussoorie"),
            ("can_go_haridwaar", "Trip to Haridwaar"),
            ("can_go_rishikesh", "Trip to Rishikesh")
        )

Migrate your Database

python manage.py makemigrations users
python manage.py migrate

Create Groups and Assign Permissions

Option A: Using Django Admin Panel

  • Login to Django admin.
  • Click on Groups.
  • Create groups like level0, level1, level2.
  • Assign relevant permissions to each group.

Option B: Programmatically Creating Groups and Assigning Permissions

Open Django shell:

python manage.py shell

Then run:

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

level0, created = Group.objects.get_or_create(name='level0')
level1, created = Group.objects.get_or_create(name='level1')
level2, created = Group.objects.get_or_create(name='level2')

user_ct = ContentType.objects.get_for_model(User)

perm_haridwar, created = Permission.objects.get_or_create(
    codename='can_go_haridwar',
    name='Can go to Haridwar',
    content_type=user_ct
)

level0.permissions.add(perm_haridwar)

Explanation:

  • Groups represent user levels (e.g., Starter, Golden, Diamond).
  • ContentType links permissions to the model (User here).
  • Permission.objects.get_or_create either fetches or creates a permission based on the codename.
  • We assign permissions to groups using .permissions.add().
  • When a user is assigned to a group, they inherit all permissions from that group.

Assign Users to Groups

You can add users to groups either through the Admin Panel or programmatically:

Python
from django.contrib.auth.models import Group
from users.models import User

user = User.objects.get(username='john')
group = Group.objects.get(name='level0')

user.groups.add(group)

Explanation:

  • We fetch a user and a group.
  • We use user.groups.add() to add the user to that group.
  • The user will then automatically have all permissions assigned to that group.

Restrict Access Based on Permissions in Views

For Function-Based Views

Use Django's built-in permission_required decorator or create a custom group-based decorator:

Python
from django.contrib.auth.decorators import user_passes_test

def group_required(*group_names):
    def in_groups(u):
        if u.is_authenticated:
            if bool(u.groups.filter(name__in=group_names)) or u.is_superuser:
                return True
        return False
    return user_passes_test(in_groups)

# Usage
@group_required('level0')
def my_view(request):
    # Your view logic here
    ...

Explanation:

  • user_passes_test runs the in_groups function to check if the user belongs to any required groups.
  • If the user is not authenticated or not in the allowed groups, access is denied.
  • This decorator protects views so only authorized groups can access them.

For Class-Based Views

Create a mixin to check group membership:

Python
from django.contrib.auth.mixins import AccessMixin

class GroupRequiredMixin(AccessMixin):
    group_required = []  # List of groups allowed to access the view

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return self.handle_no_permission()
        
        user_groups = request.user.groups.values_list('name', flat=True)
        if not any(group in user_groups for group in self.group_required):
            return self.handle_no_permission()
        
        return super().dispatch(request, *args, **kwargs)

Usage:

Python
from django.views import View

class DemoView(GroupRequiredMixin, View):
    group_required = ['admin', 'manager']
    
    def get(self, request, *args, **kwargs):
        # View logic
        ...

Explanation:

  • GroupRequiredMixin extends AccessMixin which helps to handle permission denials.
  • In dispatch method (called on every request), we check:
    • If user is authenticated.
    • If user belongs to any of the allowed groups.
  • If checks fail, access is denied (usually by redirecting to login or 403 page).
  • Otherwise, the request is processed normally.

Read Next Article: Extending and customizing django-allauth


Next Article

Similar Reads