Once we have assigned some permissions <assign>
, we can get into detail about verifying permissions of a user or group.
Normally to check if Joe is permitted to change Site
objects we call has_perm
method on an User
instance:
>>> joe.has_perm('sites.change_site')
False
And for a specific Site
instance we do the same but we pass site
as additional argument:
>>> site = Site.objects.get_current()
>>> joe.has_perm('sites.change_site', site)
False
Let's assign permission and check again:
>>> from guardian.shortcuts import assign_perm
>>> assign_perm('sites.change_site', joe, site)
<UserObjectPermission: example.com | joe | change_site>
>>> joe = User.objects.get(username='joe')
>>> joe.has_perm('sites.change_site', site)
True
This uses the backend we have specified at settings module (see configuration
). More on the backend can be found at Backend's API <guardian.backends.ObjectPermissionBackend>
.
Aside from the standard has_perm
method, django-guardian
provides some useful helpers for object permission checks.
To check permissions we can use a quick-and-dirty shortcut:
>>> from guardian.shortcuts import get_perms
>>>
>>> joe = User.objects.get(username='joe')
>>> site = Site.objects.get_current()
>>>
>>> 'change_site' in get_perms(joe, site)
True
It is probably better to use standard has_perm
method. But for Group
instances it is not as easy and get_perms
could be handy here as it accepts both User
and Group
instances. If we need to do some more work, we can use lower level ObjectPermissionChecker
class which is described in the next section.
There is also get_user_perms
to get permissions assigned directly to the user (and not inherited from its superuser status or group membership. Similarly, get_group_perms
returns only permissions which are inferred through user's group membership. get_user_perms
and get_group_perms
are useful when you care what permissions user has assigned, while has_perm
is useful when you care about user's effective permissions.
Sometimes there is a need to extract list of objects based on particular user, type of the object and provided permissions. For instance, lets say there is a Project
model at projects
application with custom view_project
permission. We want to show our users projects they can actually view. This could be easily achieved using get_objects_for_user
:
from django.shortcuts import render_to_response
from django.template import RequestContext
from projects.models import Project
from guardian.shortcuts import get_objects_for_user
def user_dashboard(request, template_name='projects/dashboard.html'):
projects = get_objects_for_user(request.user, 'projects.view_project')
return render_to_response(template_name, {'projects': projects},
RequestContext(request))
It is also possible to provide list of permissions rather than single string, own queryset (as klass
argument) or control if result should be computed with (default) or without user's groups permissions.
Documentation for get_objects_for_user
At the core
module of django-guardian
, there is a guardian.core.ObjectPermissionChecker
which checks permission of user/group for specific object. It caches results so it may be used at part of codes where we check permissions more than once.
Let's see it in action:
>>> joe = User.objects.get(username='joe')
>>> site = Site.objects.get_current()
>>> from guardian.core import ObjectPermissionChecker
>>> checker = ObjectPermissionChecker(joe) # we can pass user or group
>>> checker.has_perm('change_site', site)
True
>>> checker.has_perm('add_site', site) # no additional query made
False
>>> checker.get_perms(site)
[u'change_site']
Standard permission_required
decorator doesn't allow to check for object permissions. django-guardian
is shipped with two decorators which may be helpful for simple object permission checks but remember that those decorators hits database before decorated view is called - this means that if there is similar lookup made within a view then most probably one (or more, depending on lookups) extra database query would occur.
Let's assume we pass 'group_name'
argument to our view function which returns form to edit the group. Moreover, we want to return 403 code if check fails. This can be simply achieved using permission_required_or_403
decorator:
>>> joe = User.objects.get(username='joe')
>>> foobars = Group.objects.create(name='foobars')
>>>
>>> from guardian.decorators import permission_required_or_403
>>> from django.http import HttpResponse
>>>
>>> @permission_required_or_403('auth.change_group',
>>> (Group, 'name', 'group_name'))
>>> def edit_group(request, group_name):
>>> return HttpResponse('some form')
>>>
>>> from django.http import HttpRequest
>>> request = HttpRequest()
>>> request.user = joe
>>> edit_group(request, group_name='foobars')
<django.http.HttpResponseForbidden object at 0x102b43dd0>
>>>
>>> joe.groups.add(foobars)
>>> edit_group(request, group_name='foobars')
<django.http.HttpResponseForbidden object at 0x102b43e50>
>>>
>>> from guardian.shortcuts import assign_perm
>>> assign_perm('auth.change_group', joe, foobars)
<UserObjectPermission: foobars | joe | change_group>
>>>
>>> edit_group(request, group_name='foobars')
<django.http.HttpResponse object at 0x102b8c8d0>
>>> # Note that we now get normal HttpResponse, not forbidden
More on decorators can be read at corresponding API page <api-decorators>
.
Note
Overall idea of decorators' lookups was taken from django-authority and all credits go to it's creator, Jannis Leidel.
django-guardian
comes with special template tag guardian.templatetags.guardian_tags.get_obj_perms
which can store object permissions for a given user/group and instance pair. In order to use it we need to put following inside a template:
{% load guardian_tags %}
guardian.templatetags.guardian_tags.get_obj_perms