Introduction
Beyond CRUD, apps need custom permissions like 'publish' or 'archive'.
Key Concepts
Meta.permissions: Define in model class.
Real World Context
A CMS needs a publish_article permission separate from change_article so editors can draft content but only senior editors can make it live. Custom permissions let you model these real business workflows without conflating editing and publishing.
Deep Dive
Defining Custom Permissions
pythonclass Article(models.Model): class Meta: permissions = [ ('publish_article', 'Can publish articles'), ('feature_article', 'Can feature on homepage'), ]
Using Custom Permissions
python@permission_required('blog.publish_article', raise_exception=True) def publish(request, pk): article.status = 'published' article.save()
Common Pitfalls
- Forgetting to run migrations after adding
Meta.permissions: Custom permissions are created by migrations. If you skipmakemigrationsandmigrate, the permission does not exist in the database andhas_perm()always returnsFalse. - Using wrong app label in permission strings: The format is
app_label.codename(e.g.,blog.publish_article). Using the model name instead of the app label causes silent failures. - Not clearing the permission cache: After assigning permissions at runtime, the user object caches its permissions. You must refetch the user (
User.objects.get(pk=user.pk)) or deleteuser._perm_cacheto see the change.
Best Practices
- Define permissions in
Meta.permissions: This ensures they are created by migrations and tracked in version control. - Use
permission_requiredwithraise_exception=True: This returns a 403 Forbidden instead of silently redirecting to the login page for authenticated users who lack the permission. - Group custom permissions logically: Name codenames with a consistent pattern like
verb_model(e.g.,publish_article,archive_article) so they are easy to discover in the admin.
Summary
Define custom permissions in Meta. Use permission_required decorator.