3

I have a Django project with API based on the Django REST framework.

Recently I've enabled object-level permissions with the use of django-guardian. However I'm not using model-level permissions framework in my project yet (and until this moment I didn't see any purpose to.)

Now when I turn on DjangoObjectPermissions in my API viewset,

class PhotoViewSet(viewsets.ModelViewSet)
    permission_classes = (permissions.DjangoObjectPermissions,)

and make an update request to the endpoint for an object that has a proper "change" permission from the Guardian framework, I get a 403 FORBIDDEN response.

The reason for this response appears to lay in a request dispatch stage:

  1. DRF checks model permissions in this case.
  2. DjangoObjectPermissions inherits from DjangoModelPermissions.
  3. DRF calls DjangoObjectPermissions.has_permission()
  4. has_permission() fails because I'm not using model-level permissions.

What is a proper way to use DjangoObjectPermissions in my case?

  • (A) Implement a custom permission class, inherit it from DjangoObjectPermissions and override has_permission().
  • (B) Turn the Django's model-level permission framework on just for the sake of it.
  • (C) Use this hack workaround to skip the check.
Warwick
  • 1,200
  • 12
  • 22

1 Answers1

4

DjangoObjectPermissions is implemented in a way that expects a user to be able to edit a model as well as have permission to edit an instance of that model.

>>> from django.contrib.auth.models import User, Group
>>> user = User.objects.get(pk=1)
>>> admins = Group.objects.get(pk=1)
>>> user.has_perm('change_group')
False
>>> user.has_perm('change_group', admins)
True

Managing model permissions can add (user management) overhead to your project. I would suggest only going down this route if you have the requirement for the rest of your project and plan to use it.

Instead creating a custom permissions class that suits exactly your needs seems like the best course. It can be as simple as:

class ObjectOnlyPermissions(DjangoObjectPermissions):

    def has_permission(self, request, view):
        return True

The workaround you reference is undocumented and looks like it's there to solve an internal issue (APIRootView endpoint list being filtered). I wouldn't rely on this to fix your issue.

  • It looks like you have a typo in admin retrieval (admins -> admin). – Warwick Dec 19 '15 at 22:41
  • What kind of overhead the model permissions could add? – Warwick Dec 19 '15 at 22:42
  • By overhead I mean more user management overhead than code overhead. You need to either create and manage groups, assigning users to them, or manage each users permissions individually. Either way if your project doesn't need these features (you're only concerned with object level permissions in your application) you're adding an extra layer of complexity and management. – Ashley 'CptLemming' Wilson Dec 19 '15 at 23:25