Skip to main content

User-specific permissions with per-object support for Django + DRF

Project description

django-user-permissions

User-specific permissions with per-object support for Django + Django REST Framework.

A lightweight, API-friendly object permission system that extends Django’s default permission model with:

  • Object-level permissions – grant a permission for a specific instance
  • Ownership-based access – automatically grant view, change, delete to owners
  • DRF integration – plug-and-play support for ViewSets/APIs
  • Public/safe endpoints – make certain actions public
  • Permission caching – request-local + shared cache with automatic invalidation
  • Permission syncing – create missing default permissions automatically

Think of it as a simpler alternative to django-guardian for teams building API-first applications with Django REST Framework.


Why not just use django-guardian?

While django-guardian is powerful and battle-tested, it often requires additional setup for DRF-heavy projects.

This package focuses on:

  • automatic DRF action mapping
  • ownership rules
  • safe/public endpoints
  • reduced permission boilerplate

Requirements

  • Python 3.8+
  • Django 3.2+
  • Django REST Framework 3.14+

Installation

pip install django-user-permissions

Setup

Add to installed apps

INSTALLED_APPS = [
    ...
    "django_user_permissions",
]

Add authentication backend

Place this before Django’s default backend:

AUTHENTICATION_BACKENDS = [
    "django_user_permissions.backends.UserSpecificPermissionBackend",
    "django.contrib.auth.backends.ModelBackend",
]

Run migrations

python manage.py migrate

Sync permissions

Create missing permissions:

python manage.py sync_user_permissions

Dry run:

python manage.py sync_user_permissions --dry-run

Configuration

Add this in settings.py:

USER_PERMISSIONS = {
    "OWNERSHIP_FIELD": "user",
    "OWNER_AUTO_PERMISSIONS": ["view", "change", "delete"],
    "ALLOW_CREATE_ON_OWNERSHIP": True,

    # Actions that can be resolved at object level
    "ALLOW_OBJECT_LEVEL_ACTIONS": [
        "retrieve",
        "update",
        "partial_update",
        "destroy"
    ],

    # Allow list endpoints even if final queryset is empty
    "LIST_ALLOW_EMPTY": True,

    "MODEL_SAFE_METHODS": {
        "document": ["list", "retrieve"]
    },

    "CACHE_TTL": 300
}

DRF Integration

Example model

class Document(models.Model):
    title = models.CharField(max_length=255)
    user = models.ForeignKey(User, on_delete=models.CASCADE)

Example ViewSet

from django_user_permissions.mixins import UserSpecificPermissionMixin

class DocumentViewSet(UserSpecificPermissionMixin, ModelViewSet):
    queryset = Document.objects.all()
    serializer_class = DocumentSerializer
    auto_filter_queryset = True

auto_filter_queryset=True filters the queryset to objects the user can view (global or per-object permissions) plus objects they own—even without explicit permissions.


DRF Action Mapping

DRF Action Permission Required Example
list view_<model_name> view_document
retrieve view_<model_name> view_document
create add_<model_name> add_document
update change_<model_name> change_document
partial_update change_<model_name> change_document
destroy delete_<model_name> delete_document

Example:

PATCH /documents/1/

Requires:

change_document

How Permission Checks Work

Permission evaluation order:

  1. Superuser access
  2. Safe/public method access
  3. Global Django permissions
  4. Ownership create validation
  5. Object-specific permissions
  6. Ownership auto-permissions

Grant Object-Level Permission

from django_user_permissions.models import UserPermission
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

doc = Document.objects.get(pk=1)
perm = Permission.objects.get(codename="change_document")

UserPermission.objects.create(
    user=user,
    permission=perm,
    content_type=ContentType.objects.get_for_model(doc),
    object_id=doc.id
)

Now that user can modify only that specific document.


Caching

This package uses:

  • request-level caching
  • shared caching
  • automatic signal-based invalidation

Whenever permissions are updated/deleted, stale cache gets cleared automatically.


Management Commands

python manage.py sync_user_permissions

Supports:

  • --dry-run
  • --apps
  • --exclude

Testing

pip install -e .[dev]
pytest tests/

Use Cases

  • SaaS platforms
  • Document sharing apps
  • Project management systems
  • Multi-tenant products
  • Internal admin tools

Roadmap

  • Group object permissions
  • Queryset filtering helpers
  • Admin dashboard improvements
  • Async cache invalidation

License

MIT License


Built because writing repetitive permission logic in every DRF project gets exhausting.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_user_permissions-0.1.1.tar.gz (16.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_user_permissions-0.1.1-py3-none-any.whl (17.0 kB view details)

Uploaded Python 3

File details

Details for the file django_user_permissions-0.1.1.tar.gz.

File metadata

  • Download URL: django_user_permissions-0.1.1.tar.gz
  • Upload date:
  • Size: 16.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for django_user_permissions-0.1.1.tar.gz
Algorithm Hash digest
SHA256 1dc483f12ea776421bbbfb2e1be20faa52384a8aa8cb10554e5cdcaa64273ab5
MD5 444d8380c9d373d86df47a9794b20bce
BLAKE2b-256 baaa7b881c49d1de4991cb7be618a3c77de65a19ffc733204a27d5649de32202

See more details on using hashes here.

File details

Details for the file django_user_permissions-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for django_user_permissions-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ce36003b52c562509b4e70ff19cdb1bcc2390027bf5e056b2f6b3e0d2ba2688d
MD5 aaaa08b6a0ab82a3ec159a7bb7474d70
BLAKE2b-256 da63bee64284222295672615673de60cda57d7817413f10d7b5dd0a07b47cf9f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page