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 codename strings) for a given user/group and obj (Model instance).

Parses get_obj_perms tag 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 flatpage and perm objects 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 None as obj for this template tag won’t rise obfuscated exception and would return empty permissions set instead.