Django Admin Permissions and User Management

Django admin permissions control user access to admin interface and specific models through built-in permission system. Permission management includes user authentication, group-based permissions, model-level permissions, and object-level permissions enabling granular access control. Understanding admin permissions enables building secure multi-user applications with role-based access control, content moderation workflows, and team collaboration features. Django automatically creates add, change, delete, and view permissions for each model supporting fine-grained control over administrative capabilities. Mastering permission management supports building enterprise applications requiring sophisticated access control from simple editor/admin roles to complex hierarchical permission structures with department-specific access, workflow approvals, and audit trails ensuring data security and compliance.
Permission Basics
Django automatically creates four permissions for each model: add, change, delete, and view. Permissions are assigned to users directly or through groups enabling role-based access control. The has_perm() method checks user permissions while admin interface respects permissions automatically. Understanding permission basics enables controlling access to admin functionality.
# Permission Basics
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
from .models import Post
# Get permissions
post_ct = ContentType.objects.get_for_model(Post)
permissions = Permission.objects.filter(content_type=post_ct)
for perm in permissions:
print(f"{perm.codename}: {perm.name}")
# Output:
# add_post: Can add post
# change_post: Can change post
# delete_post: Can delete post
# view_post: Can view post
# Assign permission to user
user = User.objects.get(username='editor')
permission = Permission.objects.get(codename='add_post')
user.user_permissions.add(permission)
# Remove permission
user.user_permissions.remove(permission)
# Check permissions
if user.has_perm('blog.add_post'):
print('User can add posts')
if user.has_perm('blog.change_post'):
print('User can edit posts')
# Check multiple permissions
if user.has_perms(['blog.add_post', 'blog.change_post']):
print('User can add and edit posts')
# Groups
editors = Group.objects.create(name='Editors')
editors.permissions.add(
Permission.objects.get(codename='add_post'),
Permission.objects.get(codename='change_post'),
Permission.objects.get(codename='view_post'),
)
# Add user to group
user.groups.add(editors)
# User inherits all group permissions
print(user.get_all_permissions())
# Superuser bypass
if user.is_superuser:
print('Superuser has all permissions')
# has_perm() always returns True for superuser
# Staff status (required for admin access)
user.is_staff = True
user.save()
# Only staff users can access admin interfaceAdmin Permission Control
Admin permission control customizes what users can do in admin interface through has_add_permission, has_change_permission, and has_delete_permission methods. These methods enable dynamic permission checking based on request, object, or custom logic. Understanding admin permission control enables implementing sophisticated access rules beyond simple model permissions.
# Admin Permission Control
from django.contrib import admin
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'status']
# Control add permission
def has_add_permission(self, request):
# Only editors group can add posts
return request.user.groups.filter(name='Editors').exists()
# Control change permission
def has_change_permission(self, request, obj=None):
# Users can only edit their own posts
if obj is not None and obj.author != request.user:
return False
return True
# Control delete permission
def has_delete_permission(self, request, obj=None):
# Only superusers can delete
return request.user.is_superuser
# Control view permission
def has_view_permission(self, request, obj=None):
# Everyone with staff status can view
return request.user.is_staff
# Limit queryset based on user
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super().get_queryset(request)
if request.user.is_superuser:
return qs
# Non-superusers see only their posts
return qs.filter(author=request.user)
# Conditional field access
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None):
# Make fields readonly based on permissions
if not request.user.has_perm('blog.publish_post'):
return ['status', 'published_date']
return []
def get_fields(self, request, obj=None):
# Hide fields from certain users
fields = super().get_fields(request, obj)
if not request.user.is_superuser:
fields.remove('is_featured')
return fields
# Custom permission checking
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
def has_module_permission(self, request):
# Control access to entire model in admin
return request.user.has_perm('blog.view_post')
def has_view_permission(self, request, obj=None):
# Custom view logic
if obj:
# Check if user is in same department
return obj.author.profile.department == request.user.profile.department
return super().has_view_permission(request, obj)
# Action permissions
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
actions = ['make_published', 'make_draft']
@admin.action(description='Publish posts', permissions=['change'])
def make_published(self, request, queryset):
queryset.update(status='published')
def get_actions(self, request):
actions = super().get_actions(request)
# Remove actions based on permissions
if not request.user.has_perm('blog.publish_post'):
if 'make_published' in actions:
del actions['make_published']
return actionsCustom Permissions
Custom permissions extend default add/change/delete permissions with application-specific permissions like publish, approve, or archive. Custom permissions are defined in model Meta class and work seamlessly with Django's permission system. Understanding custom permissions enables building sophisticated workflow and approval systems.
# Custom Permissions
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
status = models.CharField(max_length=20)
class Meta:
permissions = [
('publish_post', 'Can publish posts'),
('feature_post', 'Can feature posts'),
('archive_post', 'Can archive old posts'),
]
# After migration, these permissions are available
from django.contrib.auth.models import Permission
publish_perm = Permission.objects.get(codename='publish_post')
feature_perm = Permission.objects.get(codename='feature_post')
# Assign to user
user.user_permissions.add(publish_perm)
# Check custom permission
if user.has_perm('blog.publish_post'):
post.status = 'published'
post.save()
# Use in admin
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
actions = ['publish_posts', 'feature_posts']
@admin.action(description='Publish selected posts')
def publish_posts(self, request, queryset):
if not request.user.has_perm('blog.publish_post'):
self.message_user(request, 'No permission', level='error')
return
queryset.update(status='published')
@admin.action(description='Feature posts')
def feature_posts(self, request, queryset):
if not request.user.has_perm('blog.feature_post'):
self.message_user(request, 'No permission', level='error')
return
queryset.update(is_featured=True)
# Use in views
from django.contrib.auth.decorators import permission_required
@permission_required('blog.publish_post')
def publish_post_view(request, pk):
post = get_object_or_404(Post, pk=pk)
post.status = 'published'
post.save()
return redirect('post_detail', pk=pk)
# Permission groups for roles
from django.contrib.auth.models import Group, Permission
# Create editor role
editors = Group.objects.create(name='Editors')
editors.permissions.add(
Permission.objects.get(codename='add_post'),
Permission.objects.get(codename='change_post'),
Permission.objects.get(codename='view_post'),
)
# Create publisher role
publishers = Group.objects.create(name='Publishers')
publishers.permissions.add(
Permission.objects.get(codename='publish_post'),
Permission.objects.get(codename='feature_post'),
)
# Create admin role
admins = Group.objects.create(name='Admins')
admins.permissions.add(*Permission.objects.filter(content_type__app_label='blog'))Object-Level Permissions
Object-level permissions control access to individual objects rather than entire models using packages like django-guardian. Object permissions enable scenarios where users can edit their own posts but not others. Understanding object permissions enables fine-grained access control for collaborative applications.
# Object-Level Permissions with django-guardian
# pip install django-guardian
# settings.py
INSTALLED_APPS = [
'guardian',
]
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'guardian.backends.ObjectPermissionBackend',
]
# models.py
from django.db import models
from guardian.shortcuts import assign_perm, remove_perm
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
class Meta:
permissions = [
('view_post', 'Can view post'),
('edit_post', 'Can edit post'),
]
# Assign object permission
from guardian.shortcuts import assign_perm
post = Post.objects.get(pk=1)
user = User.objects.get(username='editor')
# Give user permission to this specific post
assign_perm('view_post', user, post)
assign_perm('edit_post', user, post)
# Check object permission
from guardian.shortcuts import get_perms
if user.has_perm('blog.edit_post', post):
print('User can edit this post')
perms = get_perms(user, post)
print(f'User permissions on this post: {perms}')
# Remove permission
remove_perm('edit_post', user, post)
# Group permissions on objects
group = Group.objects.get(name='Editors')
assign_perm('edit_post', group, post)
# Get all objects user has permission for
from guardian.shortcuts import get_objects_for_user
editable_posts = get_objects_for_user(
user,
'blog.edit_post',
klass=Post
)
# Use in views
from guardian.decorators import permission_required_or_403
@permission_required_or_403('blog.edit_post', (Post, 'pk', 'pk'))
def edit_post(request, pk):
post = Post.objects.get(pk=pk)
# User has permission to edit this specific post
return render(request, 'edit.html', {'post': post})
# Use in admin
from guardian.admin import GuardedModelAdmin
@admin.register(Post)
class PostAdmin(GuardedModelAdmin):
list_display = ['title', 'author']
def has_change_permission(self, request, obj=None):
if obj is None:
return super().has_change_permission(request)
return request.user.has_perm('blog.edit_post', obj)
def get_queryset(self, request):
qs = super().get_queryset(request)
if request.user.is_superuser:
return qs
return get_objects_for_user(request.user, 'blog.view_post', qs)Permission Best Practices
Effective permission management follows patterns ensuring security and usability. Use groups for roles rather than assigning individual permissions. Create custom permissions for workflow states like publish or approve. Implement object-level permissions for collaborative features. Check permissions in views and admin methods. Provide clear permission denied messages. Test permission scenarios thoroughly. Document permission requirements for features. Use permission decorators in views. Audit permission changes for security. These practices ensure secure multi-user applications with appropriate access control supporting team collaboration and content workflows.
$ share --platform
$ cat /comments/ (0)
$ cat /comments/
// No comments found. Be the first!


