Django Guardian
django-guardian provides per-object permissions for Django, allowing fine-grained access control beyond Django's built-in model-level permissions. It enables assigning permissions to individual objects (e.g., a specific `Blog Post` instance) for specific users or groups. The library is actively maintained with frequent minor releases and bug fixes, with the current version being 3.3.1.
Warnings
- gotcha You MUST add `guardian.backends.ObjectPermissionBackend` to your `AUTHENTICATION_BACKENDS` setting for `django-guardian` to function correctly. This is a common oversight.
- deprecated The `guardian.decorators.permission_required` decorator is deprecated in favor of `guardian.decorators.api_permission_required` or, for class-based views, using `guardian.mixins.ObjectPermissionRequiredMixin` or `guardian.mixins.PermissionRequiredMixin`.
- gotcha When using Django 4.0+ with `django-guardian`, you should use `guardian.mixins.PermissionRequiredMixin` for object-level permission checks in class-based views. Do not confuse it with Django's built-in `django.contrib.auth.mixins.PermissionRequiredMixin`, which only handles model-level permissions.
- gotcha Version 3.1.0 introduced significant database indexing improvements. While migrations are designed to run automatically, users with large permission tables should be aware of potential re-indexing operations that could temporarily impact database performance during deployment of this version or later.
- gotcha For anonymous user support, ensure `ANONYMOUS_USER_NAME` is configured in `settings.py`. By default, `django-guardian` uses 'AnonymousUser'. If you customize your anonymous user, `GUARDIAN_GET_INIT_ANONYMOUS_USER` might also need configuration.
Install
-
pip install django-guardian
Imports
- assign_perm
from guardian.shortcuts import assign_perm
- remove_perm
from guardian.shortcuts import remove_perm
- get_objects_for_user
from guardian.shortcuts import get_objects_for_user
- get_perms_for_model
from guardian.shortcuts import get_perms_for_model
- ObjectPermissionRequiredMixin
from guardian.mixins import ObjectPermissionRequiredMixin
- PermissionRequiredMixin (for Django 4.0+ projects)
from guardian.mixins import PermissionRequiredMixin
Quickstart
import os
from django.conf import settings
from django.contrib.auth.models import User
from guardian.shortcuts import assign_perm, get_objects_for_user
# Minimal Django settings setup for demonstration
if not settings.configured:
settings.configure(
INSTALLED_APPS=[
'django.contrib.auth',
'django.contrib.contenttypes',
'guardian',
'myapp' # assuming a minimal app that defines a 'Book' model
],
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},
AUTHENTICATION_BACKENDS=(
'django.contrib.auth.backends.ModelBackend',
'guardian.backends.ObjectPermissionBackend',
),
ANONYMOUS_USER_NAME = 'AnonymousUser', # Important for anonymous user support
SECRET_KEY=os.environ.get('DJANGO_SECRET_KEY', 'a-very-secret-key-for-dev'),
DEBUG=True
)
# In a real project, this would be in models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='authored_books', null=True)
def __str__(self):
return self.title
class Meta:
permissions = (
('view_book', 'Can view book'),
('edit_book', 'Can edit book'),
)
# --- Example Usage ---
# Assume database is set up and migrations run (e.g., via `./manage.py migrate`)
# This is a simplified representation for demonstration.
# Create users and an object
user1 = User.objects.create_user(username='alice', password='password123')
user2 = User.objects.create_user(username='bob', password='password123')
book1 = Book.objects.create(title='The Great Adventure', author=user1)
book2 = Book.objects.create(title='Python Mastery', author=user2)
print(f"\nBook 1: {book1.title} by {book1.author}")
print(f"Book 2: {book2.title} by {book2.author}")
# Assign 'view_book' permission to user1 for book1
assign_perm('view_book', user1, book1)
print(f"\nAssigned 'view_book' to {user1.username} for {book1.title}")
# Check permissions
print(f"{user1.username} can view book1: {user1.has_perm('view_book', book1)}")
print(f"{user2.username} can view book1: {user2.has_perm('view_book', book1)}")
# Assign 'edit_book' permission to user1 for book2
assign_perm('edit_book', user1, book2)
print(f"Assigned 'edit_book' to {user1.username} for {book2.title}")
# Get objects user1 has 'view_book' permission for
user1_viewable_books = get_objects_for_user(user1, 'view_book', klass=Book)
print(f"\n{user1.username} can view: {[b.title for b in user1_viewable_books]}")
# Get objects user1 has 'edit_book' permission for
user1_editable_books = get_objects_for_user(user1, 'edit_book', klass=Book)
print(f"{user1.username} can edit: {[b.title for b in user1_editable_books]}")