User Permissions - potatoscript/django GitHub Wiki

🛡️ Django User Permissions & Authorization

In this tutorial, we will dive into user permissions and authorization in Django. Understanding how to manage who can access what in your application is crucial for maintaining security. Django provides a robust permission system that allows you to control access to different parts of your website or application.


🗂️ Step 1: Understanding Permissions

Django’s authentication system is divided into two parts:

  1. Authentication – Who is the user? (Do they have an account?)
  2. Authorization – What can the user do? (Do they have permission to access this page?)

In Django, permissions are used to determine what a user can do. There are two types of permissions you need to understand:

  • Model-level permissions – These permissions control who can add, change, or delete specific models in your application.
  • Object-level permissions – These permissions are applied to specific objects in the database (such as a blog post or comment).

Django has a default set of permissions for each model:

  • add_modelname
  • change_modelname
  • delete_modelname
  • view_modelname (in Django 2.1 and higher)

🧩 Step 2: Using Built-In Permissions

When you create a model, Django automatically provides a default set of permissions for that model. For example, let’s consider a Post model.

# models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

    def __str__(self):
        return self.title

For this model, Django automatically creates the following permissions:

  • add_post
  • change_post
  • delete_post
  • view_post

These permissions are automatically added to the database when you run migrations.

🖼️ Example: Checking Permissions in Views

You can check if a user has specific permissions by using the user.has_perm() method in your views.

# views.py
from django.shortcuts import render
from django.http import HttpResponseForbidden
from .models import Post

def post_detail(request, post_id):
    post = Post.objects.get(id=post_id)
    
    # Check if user has permission to view the post
    if not request.user.has_perm('app.view_post'):
        return HttpResponseForbidden("You do not have permission to view this post.")
    
    return render(request, 'post_detail.html', {'post': post})

In this example, if the user doesn't have permission to view the post, they are denied access and an HTTP 403 Forbidden response is returned.


🧩 Step 3: Assigning Permissions to Users

To assign permissions, you can use Django’s built-in Groups or assign individual permissions directly to a user.

🖼️ Step 3.1: Using Django Admin to Assign Permissions

  1. Login to Django Admin: If you haven't already, create an admin user using the following command:
python manage.py createsuperuser
  1. Assign Permissions to Groups:

    • Go to the Django Admin site (http://127.0.0.1:8000/admin/).
    • In the Users section, select Groups.
    • Create a new group and assign it permissions.
  2. Assign Permissions to Users:

    • Go to the Users section, click on a user.
    • In the Permissions section, check the boxes for the permissions you want to assign to the user.

🖼️ Step 3.2: Assign Permissions Programmatically

You can also assign permissions to users programmatically using Django's API.

# Assign permissions to a user programmatically
from django.contrib.auth.models import User, Permission

# Get the user and the permission
user = User.objects.get(username='john')
permission = Permission.objects.get(codename='change_post')

# Assign the permission to the user
user.user_permissions.add(permission)

🧩 Step 4: Using Custom Permissions

While Django provides default permissions like add, change, delete, and view, you might want to define custom permissions that fit the needs of your application.

🖼️ Step 4.1: Adding Custom Permissions to Models

You can define custom permissions by using the Meta class within your model.

# models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

    class Meta:
        permissions = [
            ("can_publish_post", "Can publish post"),
        ]

    def __str__(self):
        return self.title

After adding the custom permission, run migrations:

python manage.py makemigrations
python manage.py migrate

This will create the permission can_publish_post.


🧩 Step 5: Protecting Views with Permissions

You can use the @permission_required decorator to restrict access to views based on specific permissions.

# views.py
from django.contrib.auth.decorators import permission_required
from django.shortcuts import render
from .models import Post

@permission_required('app.can_publish_post', raise_exception=True)
def publish_post(request, post_id):
    post = Post.objects.get(id=post_id)
    # Logic to publish the post
    return render(request, 'publish_success.html', {'post': post})

In this case, only users with the can_publish_post permission can access the publish_post view. If they don’t have the permission, they’ll be redirected to the login page or shown an error.


🧩 Step 6: Using User Groups for Simplified Permission Management

Instead of manually assigning permissions to each user, you can organize users into groups, where each group has a specific set of permissions.

🖼️ Example: Creating and Assigning Groups

You can create a group and assign permissions to it in the Django admin, or programmatically like this:

# Create a group and assign permissions
from django.contrib.auth.models import Group, Permission

# Create the group
group, created = Group.objects.get_or_create(name='Editors')

# Get permissions and assign to group
permissions = Permission.objects.filter(codename__in=['change_post', 'can_publish_post'])
group.permissions.set(permissions)

Now, all users in the Editors group will have the change_post and can_publish_post permissions.


🧩 Step 7: Handling Object-Level Permissions

Sometimes, you need permissions that apply to specific objects. Django doesn’t handle object-level permissions out of the box, but you can implement this by extending your logic with custom decorators or third-party libraries like django-guardian.

For example, using django-guardian:

  1. Install the library:

    pip install django-guardian
    
  2. Define object-level permissions:

    # models.py
    from guardian.models import UserObjectPermissionBase
    
    class PostPermission(UserObjectPermissionBase):
        content_object = models.ForeignKey(Post, on_delete=models.CASCADE)
    
  3. Use guardian to check if a user has permissions for a specific object:

    from guardian.shortcuts import assign_perm, get_objects_for_user
    
    # Assign permission to user for a specific object
    assign_perm('can_publish_post', user, post)
    
    # Get posts the user can publish
    posts = get_objects_for_user(user, 'can_publish_post', klass=Post)
    

📝 Summary

Step What Happens
1. Understanding Permissions Learn about Django’s default and custom permissions system.
2. Using Built-In Permissions Use Django’s default model-level permissions to control access to views.
3. Assigning Permissions Learn how to assign permissions to users, either manually or through groups.
4. Custom Permissions Define and create custom permissions for more specific needs.
5. Protecting Views Protect views using the @permission_required decorator.
6. Using Groups Simplify permission management by assigning permissions to groups.
7. Object-Level Permissions Manage permissions for specific objects using third-party libraries like django-guardian.