Check object permissions¶
Once we have assigned some permissions, we can get into detail about verifying permissions of a user or group.
Standard way¶
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.
Inside views¶
Aside from the standard has_perm method, django-guardian
provides some useful helpers for object permission checks.
get_perms¶
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.
get_objects_for_user¶
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
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(request, 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.
See also
Documentation for get_objects_for_user
ObjectPermissionChecker¶
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']
Using decorators¶
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.
Note
Overall idea of decorators’ lookups was taken from django-authority and all credits go to it’s creator, Jannis Leidel.
Inside templates¶
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 %}
get_obj_perms¶
- guardian.templatetags.guardian_tags.get_obj_perms(parser, token)
Returns a list of permissions (as
codenamestrings) for a givenuser/groupandobj(Model instance).Parses
get_obj_permstag which should be in format:{% get_obj_perms user/group for obj as "context_var" %}
Note
Make sure that you set and use those permissions in same template block (
{% block %}).Example of usage (assuming
flatpageandpermobjects are available from context):{% get_obj_perms request.user for flatpage as "flatpage_perms" %} {% if "delete_flatpage" in flatpage_perms %} <a href="/pages/delete?target={{ flatpage.url }}">Remove page</a> {% endif %}
Note
Please remember that superusers would always get full list of permissions for a given object.
New in version 1.2.
As of v1.2, passing
Noneasobjfor this template tag won’t rise obfuscated exception and would return empty permissions set instead.