User Groups with Custom Permissions in Django Python (original) (raw)

Last Updated : 24 May, 2025

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

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:

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:

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:

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:

**Read Next Article: **Extending and customizing django-allauth