Ready to implement Row Level Security in your Django application? This guide will walk you through everything you need to get started with Django RLS, from installation to your first policy.
Prerequisites
Before you begin, ensure you have:
- Django 3.2+ installed
- PostgreSQL 9.5+ as your database (RLS requires PostgreSQL)
- Python 3.7+
- Basic knowledge of Django models and migrations
Step 1: Install Django RLS
Install the package using pip:
pip install django-rls
Add it to your INSTALLED_APPS:
# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_rls', # Add this
'your_app',
]
Step 2: Add the RLS Middleware
Add Django RLS middleware to automatically manage context:
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django_rls.middleware.RLSMiddleware', # Add this
]
Step 3: Convert Your Models to RLS Models
Instead of inheriting from models.Model, inherit from RLSModel:
# models.py
from django.db import models
from django_rls.models import RLSModel
from django_rls.policies import UserPolicy
class Document(RLSModel): # Changed from models.Model
title = models.CharField(max_length=200)
content = models.TextField()
owner = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
related_name='documents'
)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
# Define your RLS policies here
rls_policies = [
UserPolicy('owner_policy', user_field='owner')
]
def __str__(self):
return self.title
Step 4: Create and Run Migrations
Django RLS automatically creates the necessary PostgreSQL RLS policies through migrations:
python manage.py makemigrations
python manage.py migrate
Django RLS will create:
- The database table (like normal)
- PostgreSQL RLS policies based on your configuration
- Migration files for tracking changes
Step 5: Use Your Model
Now you can use your model normally, but with automatic RLS protection:
# views.py
from django.shortcuts import render
from .models import Document
def document_list(request):
# This query automatically respects RLS policies
# User only sees their own documents
documents = Document.objects.all()
return render(request, 'documents/list.html', {'documents': documents})
def document_detail(request, pk):
# Even accessing a specific document is protected by RLS
document = Document.objects.get(pk=pk)
return render(request, 'documents/detail.html', {'document': document})
Step 6: Create in Django Admin
Django admin works seamlessly with RLS:
# admin.py
from django.contrib import admin
from .models import Document
@admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
list_display = ['title', 'owner', 'created_at']
readonly_fields = ['created_at']
Admin users will automatically see only documents they own (or all if they have appropriate permissions).
Common Use Cases
1. User-Owned Documents
class Document(RLSModel):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
rls_policies = [
UserPolicy('owner_policy', user_field='owner')
]
Each user sees only their own documents.
2. Multi-Tenant SaaS
class Document(RLSModel):
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE)
class Meta:
rls_policies = [
TenantPolicy('tenant_isolation', tenant_field='tenant')
]
Each tenant sees only their own data.
3. Team-Based Access
class Document(RLSModel):
team = models.ForeignKey(Team, on_delete=models.CASCADE)
class Meta:
rls_policies = [
# Define a team policy that allows all team members
]
4. Shared Documents with Ownership
class Document(RLSModel):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
shared_with = models.ManyToManyField(User, related_name='shared_documents')
class Meta:
rls_policies = [
# Policy that shows owned documents + shared documents
]
Testing Your Implementation
Use Django RLS’s test utilities:
# tests.py
from django.contrib.auth.models import User
from django_rls.test_utils import RLSTestCase
from .models import Document
class DocumentTestCase(RLSTestCase):
def setUp(self):
super().setUp()
self.user1 = User.objects.create_user('user1', '[email protected]', 'pass')
self.user2 = User.objects.create_user('user2', '[email protected]', 'pass')
def test_user_isolation(self):
# Create document as user1
doc1 = Document.objects.create(
title='User 1 Doc',
owner=self.user1
)
# Set context to user1
self.set_user_context(self.user1)
# User1 can see their document
self.assertEqual(Document.objects.count(), 1)
self.assertEqual(Document.objects.first(), doc1)
# Switch to user2
self.set_user_context(self.user2)
# User2 can't see user1's document
self.assertEqual(Document.objects.count(), 0)
Troubleshooting
Policy Not Showing Effect
- Ensure middleware is installed - RLS requires context to be set
- Check database user permissions - The PostgreSQL user needs RLS enabled
- Verify migrations ran - Run
python manage.py migrate
Performance Issues
-
Add database indexes - RLS conditions work with indexes:
class Document(RLSModel): owner = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True) -
Use select_related for foreign keys:
documents = Document.objects.select_related('owner').all()
Next Steps
Now that you’ve set up Django RLS:
- Explore the documentation - Read about advanced policies and custom rules
- Check out examples - Look at the Django RLS GitHub repository
- Join the community - Participate in discussions and ask questions on the forum
- Test thoroughly - Write comprehensive tests for your RLS policies
Quick Reference
Import statements:
from django_rls.models import RLSModel
from django_rls.policies import UserPolicy, TenantPolicy
from django_rls.test_utils import RLSTestCase
Settings required:
INSTALLED_APPS = [..., 'django_rls', ...]
MIDDLEWARE = [..., 'django_rls.middleware.RLSMiddleware', ...]
Model structure:
class MyModel(RLSModel):
# Your fields
class Meta:
rls_policies = [...] # Define policies here
You’re now ready to implement database-level Row Level Security in your Django applications!