{"id":4507,"library":"django-guardian","title":"Django Guardian","description":"django-guardian provides per-object permissions for Django, allowing fine-grained access control beyond Django's built-in model-level permissions. It enables assigning permissions to individual objects (e.g., a specific `Blog Post` instance) for specific users or groups. The library is actively maintained with frequent minor releases and bug fixes, with the current version being 3.3.1.","status":"active","version":"3.3.1","language":"en","source_language":"en","source_url":"https://github.com/django-guardian/django-guardian","tags":["django","permissions","authorization","access-control"],"install":[{"cmd":"pip install django-guardian","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core framework dependency, version compatibility is crucial. Requires Django >= 3.2.","package":"Django","optional":false}],"imports":[{"symbol":"assign_perm","correct":"from guardian.shortcuts import assign_perm"},{"symbol":"remove_perm","correct":"from guardian.shortcuts import remove_perm"},{"symbol":"get_objects_for_user","correct":"from guardian.shortcuts import get_objects_for_user"},{"symbol":"get_perms_for_model","correct":"from guardian.shortcuts import get_perms_for_model"},{"note":"The `permission_required` decorator is deprecated; mixins or `api_permission_required` are preferred, especially for class-based views.","wrong":"from guardian.decorators import permission_required","symbol":"ObjectPermissionRequiredMixin","correct":"from guardian.mixins import ObjectPermissionRequiredMixin"},{"note":"When using `django-guardian` with Django 4.0+, use `guardian.mixins.PermissionRequiredMixin` for object permissions instead of Django's built-in mixin, which is for model-level permissions only.","wrong":"from django.contrib.auth.mixins import PermissionRequiredMixin","symbol":"PermissionRequiredMixin (for Django 4.0+ projects)","correct":"from guardian.mixins import PermissionRequiredMixin"}],"quickstart":{"code":"import os\nfrom django.conf import settings\nfrom django.contrib.auth.models import User\nfrom guardian.shortcuts import assign_perm, get_objects_for_user\n\n# Minimal Django settings setup for demonstration\nif not settings.configured:\n    settings.configure(\n        INSTALLED_APPS=[\n            'django.contrib.auth',\n            'django.contrib.contenttypes',\n            'guardian',\n            'myapp' # assuming a minimal app that defines a 'Book' model\n        ],\n        DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},\n        AUTHENTICATION_BACKENDS=(\n            'django.contrib.auth.backends.ModelBackend',\n            'guardian.backends.ObjectPermissionBackend',\n        ),\n        ANONYMOUS_USER_NAME = 'AnonymousUser', # Important for anonymous user support\n        SECRET_KEY=os.environ.get('DJANGO_SECRET_KEY', 'a-very-secret-key-for-dev'),\n        DEBUG=True\n    )\n\n# In a real project, this would be in models.py\nfrom django.db import models\nclass Book(models.Model):\n    title = models.CharField(max_length=255)\n    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='authored_books', null=True)\n\n    def __str__(self):\n        return self.title\n\n    class Meta:\n        permissions = (\n            ('view_book', 'Can view book'),\n            ('edit_book', 'Can edit book'),\n        )\n\n# --- Example Usage ---\n\n# Assume database is set up and migrations run (e.g., via `./manage.py migrate`)\n# This is a simplified representation for demonstration.\n\n# Create users and an object\nuser1 = User.objects.create_user(username='alice', password='password123')\nuser2 = User.objects.create_user(username='bob', password='password123')\nbook1 = Book.objects.create(title='The Great Adventure', author=user1)\nbook2 = Book.objects.create(title='Python Mastery', author=user2)\n\nprint(f\"\\nBook 1: {book1.title} by {book1.author}\")\nprint(f\"Book 2: {book2.title} by {book2.author}\")\n\n# Assign 'view_book' permission to user1 for book1\nassign_perm('view_book', user1, book1)\nprint(f\"\\nAssigned 'view_book' to {user1.username} for {book1.title}\")\n\n# Check permissions\nprint(f\"{user1.username} can view book1: {user1.has_perm('view_book', book1)}\")\nprint(f\"{user2.username} can view book1: {user2.has_perm('view_book', book1)}\")\n\n# Assign 'edit_book' permission to user1 for book2\nassign_perm('edit_book', user1, book2)\nprint(f\"Assigned 'edit_book' to {user1.username} for {book2.title}\")\n\n# Get objects user1 has 'view_book' permission for\nuser1_viewable_books = get_objects_for_user(user1, 'view_book', klass=Book)\nprint(f\"\\n{user1.username} can view: {[b.title for b in user1_viewable_books]}\")\n\n# Get objects user1 has 'edit_book' permission for\nuser1_editable_books = get_objects_for_user(user1, 'edit_book', klass=Book)\nprint(f\"{user1.username} can edit: {[b.title for b in user1_editable_books]}\")\n","lang":"python","description":"This quickstart demonstrates the core functionality of `django-guardian`: setting up the `ObjectPermissionBackend`, assigning per-object permissions using `assign_perm`, checking permissions with `has_perm`, and retrieving objects a user has specific permissions for using `get_objects_for_user`."},"warnings":[{"fix":"Add `'guardian.backends.ObjectPermissionBackend'` to your `AUTHENTICATION_BACKENDS` tuple in `settings.py`. Ensure it's listed after `django.contrib.auth.backends.ModelBackend` if you still want default Django authentication.","message":"You MUST add `guardian.backends.ObjectPermissionBackend` to your `AUTHENTICATION_BACKENDS` setting for `django-guardian` to function correctly. This is a common oversight.","severity":"gotcha","affected_versions":"All versions"},{"fix":"For function-based API views, use `api_permission_required`. For class-based views, inherit from `ObjectPermissionRequiredMixin` (for all Django versions) or `PermissionRequiredMixin` (for Django 4.0+ projects).","message":"The `guardian.decorators.permission_required` decorator is deprecated in favor of `guardian.decorators.api_permission_required` or, for class-based views, using `guardian.mixins.ObjectPermissionRequiredMixin` or `guardian.mixins.PermissionRequiredMixin`.","severity":"deprecated","affected_versions":">=3.1.2"},{"fix":"Always import `PermissionRequiredMixin` from `guardian.mixins` for object-level permission requirements in views.","message":"When using Django 4.0+ with `django-guardian`, you should use `guardian.mixins.PermissionRequiredMixin` for object-level permission checks in class-based views. Do not confuse it with Django's built-in `django.contrib.auth.mixins.PermissionRequiredMixin`, which only handles model-level permissions.","severity":"gotcha","affected_versions":">=3.1.0 (with Django >= 4.0)"},{"fix":"Ensure database backups are performed before migrating to 3.1.0 or later on production systems. Monitor database performance during and after applying migrations.","message":"Version 3.1.0 introduced significant database indexing improvements. While migrations are designed to run automatically, users with large permission tables should be aware of potential re-indexing operations that could temporarily impact database performance during deployment of this version or later.","severity":"gotcha","affected_versions":">=3.1.0"},{"fix":"Add `ANONYMOUS_USER_NAME = 'YourCustomAnonymousUserName'` to `settings.py` if your anonymous user is named differently. Consider `GUARDIAN_GET_INIT_ANONYMOUS_USER` if you need a custom anonymous user object initialization.","message":"For anonymous user support, ensure `ANONYMOUS_USER_NAME` is configured in `settings.py`. By default, `django-guardian` uses 'AnonymousUser'. If you customize your anonymous user, `GUARDIAN_GET_INIT_ANONYMOUS_USER` might also need configuration.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-12T00:00:00.000Z","next_check":"2026-07-11T00:00:00.000Z"}