In a Django project and application just created with django-admin startproject
and ./manage.py startapp
, I've created this model:
class Book(models.Model):
author = models.CharField(max_length=50)
Then I run this code with ./manage.py shell
:
from django.contrib.auth.models import Permission, User
from django.test import TestCase
from myapp.models import Book
myuser = User.objects.create_user(username="myuser")
myuser.user_permissions.add(Permission.objects.get(codename="change_book"))
mybook = Book(author="Joe Author")
mybook.save()
myuser.has_perm("myapp.change_book")) # The result is True
myuser.has_perm("myapp.change_book", mybook)) # The result is False
Why is this? The user does have permission to edit mybook
, doesn't he? How is has_perm()
supposed to work? Is this documented somewhere?
The has_perm()
API is designed to work with both model-level permissions (second parameter is None
) and object-level permissions. It's up to individual authentication backends, however, to determine what to support.
In the case of Django's default ModelBackend
there is no support for object-level permissions:
Django’s permission framework has a foundation for object permissions, though there is no implementation for it in the core. That means that checking for object permissions will always return
False
.
This is also noted in the ModelBackend
documentation.
Note that the backend must return False
here since the results from individual backends are, in essence, OR'ed together. If this backend returned True
it wouldn't be possible to respect the finer-grained results from other backends.
And there are backends that implement object-level permissions, django-guardian being perhaps the best known. See how it documents has_perm()
:
Main difference between Django's
ModelBackend
is that we can passobj
instance here.