Default Model Permissions
For every model, Django automatically creates four permissions during migration: add_<model>, change_<model>, delete_<model>, and view_<model>, stored in the auth_permission table and identified by a string like 'app_label.add_article'. You check them with user.has_perm('app_label.add_article'), which returns True if the permission is assigned either directly to the user or through any Group the user belongs to.
Cricket analogy: The four default permissions are like a ground's standard access tiers — pavilion entry, nets access, dressing-room access, and press-box access — automatically issued per venue without a groundskeeper hand-crafting each one.
Custom Permissions and Object-Level Checks
You can define additional permissions beyond the default four inside a model's Meta class using permissions = [('can_publish', 'Can publish articles')], which get created alongside the standard ones and checked the same way via has_perm(). Django's built-in ModelBackend only supports model-level permissions (not per-object), so for object-level checks — like 'can this user edit this specific article' — you typically need a third-party package like django-guardian or custom logic comparing article.author == request.user directly in the view.
Cricket analogy: A custom permission like can_publish is like a board issuing a special 'match referee' credential beyond the standard player/umpire tiers — a bespoke role added for a specific need not covered by default access levels.
Groups as Reusable Permission Bundles
A Group (django.contrib.auth.models.Group) is simply a named collection of permissions that you assign to a user via user.groups.add(group_instance), letting you manage access for entire teams — like 'Editors' or 'Moderators' — in one place instead of assigning permissions to hundreds of users individually. Since has_perm() checks both direct user permissions and group-derived permissions, updating a Group's permission set instantly changes access for every member without touching individual user records.
Cricket analogy: A Group is like a squad's 'central contract' tier that bundles match fees, insurance, and central pool bonuses into one package — update the tier once and every contracted player's benefits change together.
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.models import Group, Permission
# Assigning a user to a group (e.g. in a data migration or admin action)
editors_group, _ = Group.objects.get_or_create(name='Editors')
publish_perm = Permission.objects.get(codename='can_publish')
editors_group.permissions.add(publish_perm)
user.groups.add(editors_group)
@permission_required('articles.can_publish', raise_exception=True)
def publish_article(request, pk):
article = get_object_or_404(Article, pk=pk)
article.is_published = True
article.save()
return redirect('article-detail', pk=pk)Superusers (is_superuser=True) automatically pass every has_perm() check regardless of assigned permissions or groups — useful for admin accounts but a reason to be careful about who gets superuser status.
Django's default ModelBackend permission checks are model-level, not object-level. has_perm('articles.change_article') tells you the user can change *some* article, not necessarily this specific one — always add explicit ownership checks (like article.author == request.user) for per-object protection unless you're using a package like django-guardian.
- Django auto-creates add, change, delete, and view permissions for every model.
- Custom permissions are declared in a model's Meta.permissions list.
- user.has_perm('app_label.codename') checks both direct and group-derived permissions.
- Groups bundle permissions so access can be managed for teams, not individual users.
- Default permission checks are model-level; object-level checks require extra logic or django-guardian.
- Superusers bypass all permission checks automatically.
- @permission_required protects views the same way @login_required protects authentication.
Practice what you learned
1. Which four permissions does Django automatically create for every model?
2. How do you define an additional permission beyond the default four?
3. What does user.has_perm('app_label.change_article') check?
4. What is the purpose of a Group in Django's auth system?
5. How do you achieve true per-object permission checks (e.g., 'can edit this specific article') in Django?
Was this page helpful?
You May Also Like
User Authentication in Django
Django's auth framework provides a User model, session-based login/logout, password hashing, and decorators to protect views — all ready to use out of the box.
Django Sessions
Django's session framework stores per-visitor state server-side, keyed by a signed cookie, enabling features like login state and shopping carts across stateless HTTP requests.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentNext.js Study Notes
JavaScript · 30 topics