Skip to main content
Version: 2.1

Introduction

Django RLS provides PostgreSQL Row Level Security (RLS) capabilities for Django applications, implementing true database-level security rather than application-layer filtering.

Created by Kuldeep Pisda - Full-stack developer specializing in Django and PostgreSQL

What is Row Level Security?​

Row Level Security (RLS) is a PostgreSQL feature that enables fine-grained access control at the row level. When RLS is enabled on a table, PostgreSQL automatically filters rows based on policies you define, ensuring users can only see and modify data they're authorized to access.

Why Django RLS?​

  • Database-Level Security: Security is enforced by PostgreSQL, not your application code
  • Performance: Filtering happens at the database level, often more efficiently
  • Consistency: No risk of forgetting to filter querysets in your views
  • Simplicity: Define policies once, apply everywhere
  • Django Integration: Seamless integration with Django's ORM and middleware

Key Features​

  •   True database-level Row Level Security with FORCE RLS
  •   Built-in tenant-based and user-based policies
  •   Extensible policy system for custom rules
  •   Secure context management (middleware + system_rls_context())
  •   Security regression suite against live PostgreSQL
  •   Django-style API following DRF patterns
Version 2.1

This documentation describes 2.1, which adds background task support for Celery, django.tasks and other queues. Upgrading from 0.4.x? The security hardening released as 1.0.0 (published on PyPI as 2.0.0) is not backward compatible; see Migrating from 0.4.x.

How It Works​

  1. Define Models: Inherit from RLSModel instead of Django's Model
  2. Add Policies: Define RLS policies in your model's Meta class
  3. Middleware: Automatically sets user/tenant context from requests
  4. Transparent: Your views and querysets work normally - filtering is automatic

Example​

from django_rls.models import RLSModel
from django_rls.policies import UserPolicy

class Document(RLSModel):
title = models.CharField(max_length=200)
content = models.TextField()
owner = models.ForeignKey(User, on_delete=models.CASCADE)

class Meta:
rls_policies = [
UserPolicy('owner_policy', user_field='owner'),
]

With this setup, users automatically see only their own documents - no additional filtering needed in your views!