Django Rest Framework Permissions and Ownership

django permissions
django rest framework permissions per method
django rest framework group permissions
django rest framework authentication
django object level permissions
django rest framework jwt
django custom permissions
django rest framework roles

I have two simple models

class User(AbstractUser): 
    pass


class Vacation(Model):
    id    = models.AutoField(primary_key=True)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

I am not really sure what is the scalable way of doing user permissions for Django Rest Framework. In particular:

  • Users should only be able to see their own vacations
  • On the /vacation endpoint, user would see a filtered list
  • On the /vacation/$id endpoint, user would get a 403 if not owner
  • Users should only be able to Create/Update vacations as long as they are the owners of that object (through Foreign Key)

What is the best way to achieve this in a future-proof fashion. Say if further down the line:

  • I add a different user type, which can view all vacations, but can only create/update/delete their own
  • I add another model, where users can read, but cannot write

Thank you!

From the docs:

Permissions in REST framework are always defined as a list of permission classes. Before running the main body of the view each permission in the list is checked. If any permission check fails an exceptions.PermissionDenied or exceptions.NotAuthenticated exception will be raised, and the main body of the view will not run.

REST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.

For your current need you can define your own Permission class:

class IsVacationOwner(permissions.BasePermission):
    # for view permission
    def has_permission(self, request, view):
        return request.user and request.user.is_authenticated

    # for object level permissions
    def has_object_permission(self, request, view, vacation_obj):
        return vacation_obj.owner.id == request.user.id

And add this permission to your view. For example on a viewset:

class VacationViewSet(viewsets.ModelViewSet):
    permission_classes = (IsVacationOwner,)

One thing is important to notice here, since you will respond with a filtered list for '/vacations', make sure you filter them using the request.user. Because object level permission will not be applicable for lists.

For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.

For your future requirement, you can always set the permissions conditionally with the help of get_permissions method.

class VacationViewSet(viewsets.ModelViewSet):
    def get_permissions(self):
        if self.action == 'list':
            # vacations can be seen by anyone
            # remember to remove the filter for list though
            permission_classes = [IsAuthenticated] 

            # or maybe that special type of user you mentioned
            # write a `IsSpecialUser` permission class first btw
            permission_classes = [IsSpecialUser] 
        else:
            permission_classes = [IsVacationOwner]

        return [permission() for permission in permission_classes]

DRF has great documentation. I hope this helps you to get started and helps you to approach different use cases according to your future needs.

4 - Authentication and permissions, Add the following two fields to the Snippet model in models.py . owner = models. ForeignKey('auth.User',� Django rest framework provides in-build settings for this. Just import the required permission and add it to you class variable permission_classes. in my_name.api.views. from rest_framework.permissions import ( AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly,) class Vacation(ListAPIView): serializer_class = VacationListSerializer permission_classes = [IsAuthenticated]

I would suggest you to use drf-viewsets link. We are going to use vacation viewset to do this work.

our urls.py
from your_app.views import VacationViewSet
router.register('api/vacations/', VacationViewSet)
our serializers.py
from rest_framework import serializers
from your_app.models import Vacation

class VacationSerializer(serializers.ModelSerializer):

    class Meta:
        model = Vacation
        fields = ('id', 'owner',)
        read_only_fields = ('id',)
our views.py

Here we are going to overwrite viewset's retrive and list method. There are other possible way to do that but i like this most as i can able to see what is happening in code. Django model viewset inherited link of drf-mixins retrive and list method.

from rest_framework import viewsets, permissions, exceptions, status
from your_app.models import Vacation, User
from your_app.serializers import VacationSerializer 


class VacationViewSet(viewsets.ModelViewSet):
    queryset = Vacation.objects.all()
    permission_classes = [IsAuthenticated]
    serializer = VacationSerializer

    # we are going to overwrite list and retrive
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        # now we are going to filter on user 
        queryset = queryset.filter(owner=self.request.user) 
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        # not permitted check
        if instance.owner is not self.request.user:
             raise exceptions.PermissionDenied()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

Django Rest Framework owner permissions, IsOwnerOrReject is permission class that match the user to current login user otherwise it rejects. In your case you have to define custom� Any global settings for a REST framework API are kept in a single configuration dictionary named REST_FRAMEWORK. Start off by adding the following to your settings.py module: REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users.

Django rest framework provides in-build settings for this

Just import the required permission and add it to you class variable permission_classes

in my_name.api.views

from rest_framework.permissions import ( AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly,)

class Vacation(ListAPIView):
    serializer_class = VacationListSerializer
    permission_classes = [IsAuthenticated]

You can add multiple permission classes as a list

Furthur, in case this is not helpful, you can always filter the model objects as

Mymodel.objects.filter(owner = self.request.user)

IsOwner, For this, you must edit your ViewSet. Like this exemplo, only the owner of the product can view it. from rest_framework.authentication import� So let's see about handling these permissions. 2:25. So I'm gonna hop back over here to views.py and. 2:29. I need to add an import, so that I'll go here. 2:33. From rest_framework import permissions, 2:38. and I'm gonna focus on the Django model permissions class. 2:42. So like I said, I've already added the user with a single permission, so. 2:45

Permissions - Django REST framework, Django, API, REST, Permissions, API Reference, Custom permissions, Third party packages. REST framework permissions also support object-level permissioning. Object level Assumes the model instance has an `owner` attribute. Permissions In Django Rest Framework¶ Permissions in Django Rest Framework are used to grant or deny access for different types of users to different parts of the API. Permissions are very useful when serving API resources/end-points with certain restrictions.

Permissions In Django Rest Framework, permissions in Django Rest Framework are used to grant or deny access for writer scenario where user writes books and if only allow its owner to modify it. from rest_framework import permissions class IsOwnerOrReadOnly(permissions.BasePermission): """ Custom permission to only allow owners of an object to edit it. """ def has_object_permission(self, request, view, obj): # Read permissions are allowed to any request, # so we'll always allow GET, HEAD or OPTIONS requests.

Adding Object Level Permissions in Django REST Framework (Part 8), framework. Blog post part of dockerized Django API with Angular app tutorial series. In this article, you'll learn how to add object level permissions in Django REST Framework (DRF). This post is part of title = models. Rules based permissions for the Django Rest Framework. News 📢 This project is a fork from @dbkaplan/dry-rest-permissions , multiple peoples tried to contact the old maintener but the community had no news from him in the last two years and the package was completely out of date.

Comments
  • Thank you for your answer, but that does not answer the question. How would I ensure that a user can only CRUD their own vacations?
  • Thank you for your addition. For the filtering part, what if in the future I have 2 types of users: one where I need to filter and one where I don't?
  • add permission classes to the specific class. In your case IsOwner class
  • In that case you need to check if the request user is among the users who can access the View.