Skip to main content

Overview

Django Guardian provides object-level permissions for Django models, allowing you to control access at the individual object level rather than just model-wide. Unfold’s integration ensures that Guardian’s permission management interface matches your admin’s modern design.
Object permissions enable fine-grained access control, such as allowing a user to edit only their own posts, not all posts.

Installation

1

Install django-guardian

Install the package using pip:
pip install django-guardian
2

Add to INSTALLED_APPS

Add both unfold.contrib.guardian and guardian to your settings:
settings.py
INSTALLED_APPS = [
    "unfold",
    "unfold.contrib.guardian",  # Must come before guardian
    
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    # ...
    
    "guardian",
]
3

Configure authentication backend

Add Guardian’s authentication backend to your settings:
settings.py
AUTHENTICATION_BACKENDS = [
    "django.contrib.auth.backends.ModelBackend",  # Default backend
    "guardian.backends.ObjectPermissionBackend",
]
4

Run migrations

Apply Guardian’s database migrations:
python manage.py migrate

How It Works

The unfold.contrib.guardian app overrides all templates provided by django-guardian with Unfold-styled versions. This ensures:
  • Consistent visual design across your admin interface
  • Proper integration with Unfold’s color scheme and typography
  • Support for both light and dark modes
  • Responsive layout for mobile devices
No additional configuration is needed in your admin classes. Guardian automatically adds an “Object permissions” button to your change forms.

Usage Example

Basic Model Setup

Configure your models to work with Guardian:
models.py
from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        permissions = [
            ("view_private_article", "Can view private article"),
            ("edit_article_metadata", "Can edit article metadata"),
        ]

Admin Configuration

admin.py
from django.contrib import admin
from unfold.admin import ModelAdmin
from .models import Article

@admin.register(Article)
class ArticleAdmin(ModelAdmin):
    list_display = ["title", "author", "created_at"]
    list_filter = ["created_at"]
    search_fields = ["title", "content"]

Assigning Permissions

Use Guardian’s API to assign object-level permissions:
views.py
from guardian.shortcuts import assign_perm, remove_perm
from .models import Article

# Assign permission
article = Article.objects.get(id=1)
assign_perm("change_article", user, article)
assign_perm("view_private_article", group, article)

# Remove permission
remove_perm("change_article", user, article)

Checking Permissions

from guardian.shortcuts import get_objects_for_user

# Get all articles user can change
articles = get_objects_for_user(user, "myapp.change_article")

# Check if user has permission
if user.has_perm("change_article", article):
    # User can change this specific article
    pass

Object Permissions Button

When viewing an object’s change form, Guardian adds an “Object permissions” button that opens a dedicated interface for managing permissions:
Object permissions button

Permission Management Interface

The permissions interface allows you to:
  • View all users and groups with permissions for the object
  • Assign new permissions to users or groups
  • Remove existing permissions
  • See inherited permissions from groups
Use the search functionality to quickly find users or groups when assigning permissions to large teams.

Advanced Features

Per-Object Permissions in Admin

Customize which users see which objects in the admin:
admin.py
from django.contrib import admin
from unfold.admin import ModelAdmin
from guardian.admin import GuardedModelAdmin
from .models import Article

@admin.register(Article)
class ArticleAdmin(ModelAdmin, GuardedModelAdmin):
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return get_objects_for_user(
            request.user, 
            "myapp.view_article",
            qs
        )

Custom Permission Checks

Implement custom permission logic:
admin.py
class ArticleAdmin(ModelAdmin):
    def has_change_permission(self, request, obj=None):
        if obj is None:
            return super().has_change_permission(request)
        return request.user.has_perm("change_article", obj)
    
    def has_delete_permission(self, request, obj=None):
        if obj is None:
            return super().has_delete_permission(request)
        return request.user.has_perm("delete_article", obj)

Live Demo

Explore Django Guardian Integration

View object permissions management in action with Unfold’s styled interface

Common Use Cases

Restrict users to only see and edit objects belonging to their organization:
# Assign all org objects to org members
for obj in organization.objects.all():
    assign_perm("view_object", org_member, obj)
    assign_perm("change_object", org_member, obj)
Allow specific users to collaborate on documents:
# Share document with collaborators
for collaborator in document.collaborators.all():
    assign_perm("change_document", collaborator, document)
    assign_perm("view_document", collaborator, document)
Implement role-based permissions with different access levels:
# Managers can change, staff can view
assign_perm("change_report", manager_group, report)
assign_perm("view_report", staff_group, report)

Resources

Django Guardian Docs

Official documentation and API reference

GitHub Repository

Source code and issue tracker
Object permissions are stored in the database and can impact performance on large datasets. Consider caching strategies for production use.

Build docs developers (and LLMs) love