I'm a newbie in developing with Django + Django Rest-framework and I'm working on a project that provides REST Api access. I was wondering what is the best practice to assign a different permission to each action of a given ApiView or Viewset.
Let's suppose I defined some permissions classes such as 'IsAdmin', 'IsRole1', 'IsRole2', ..., and I want to grant different permissions to the single actions (e.g. a user with Role1 can create or retrieve, a user with Role2 can update, and only an Admin can delete).
How can I structure a class based view in order to assign a permission class to the 'create', 'list', 'retrieve', 'update', 'delete' actions? I'm trying to do so to have a class that can be reused for different tables that have the same permission pattern.
Maybe I'm just drowning in an inch of water, thank you for your replies.
Django has a persmissions class called DjangoObjectPermissions which uses Django Guardian as an authentication backend.
When you have Django guardian active in your settings you just add
permission_classes = [DjandoObjectPermissions]
to your view and it does permission authentication automatically, so you can 'CRUD' based on the permission set to a particulardjango.contrib.auth
group or user.See a gist with an example.
You can set Django Guardian as your authentication backed http://django-guardian.readthedocs.org/en/latest/installation.html
You can create a custom permission class extending DRF's
BasePermission
.You implement
has_permission
where you have access to therequest
andview
objects. You can checkrequest.user
for the appropriate role and returnTrue
/False
as appropriate.Have a look at the provided IsAuthenticatedOrReadOnly class (and others) for a good example of how easy it is.
I hope that helps.
RestFramework's class-based views have methods for each HTTP verb (ie : HTTP GET => view.get() etc). You just have to use django.contrib.auth's permissions, users, groups and decorators as documented.
I personally hate this kind of frankenmonster custom permissions, in my opinion, it's not very idiomatic when it comes to Django framework; So I came up with the following solution - it's very similar to how
@list_route
and@detail_route
decorators work. We are relying on the fact that the methods/functions are first class objectsFirst of all I'm creating such decorator:
decorators.py
As you can see it adds a dictionary to the function it decorates with parameters passed as arg list
Now I created such mixin: mixins.py
Mixin does two things; when
get_permissions
is called, it checks which 'action' is executed, and looksup the permission_classes collection from theroute_action_kwargs
associated with theviewset.action_method.route_action_kwargs
when
get_serializer_class
is called, it does the same and picks theserializer
fromroute_action_kwargs
Now the way we can use it:
For custom routs we define explicitly we can just set the
@route_action_arguments
explicitly on the method.In terms of generic viewsets and methods, we can still add them using the
@method_decorator
In DRF documentation,
Let's assume following permission about
user
objectpermissons.py
views.py
EDIT
For Django 2.0 replace
is_authenticated()
withis_authenticated
. The method has been turned into an attribute.