Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST framework: help on object level permission

Following this tutorial:

http://django-rest-framework.org/tutorial/1-serialization.html

through http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html

I have this code:

# models.py
class Message(BaseDate):
    """
    Private Message Model
    Handles private messages between users
    """
    status = models.SmallIntegerField(_('status'), choices=choicify(MESSAGE_STATUS))
    from_user = models.ForeignKey(User, verbose_name=_('from'), related_name='messages_sent')
    to_user = models.ForeignKey(User, verbose_name=_('to'), related_name='messages_received')
    text = models.TextField(_('text'))
    viewed_on = models.DateTimeField(_('viewed on'), blank=True, null=True)


# serialisers.py
class MessageSerializer(serializers.ModelSerializer):
    from_user = serializers.Field(source='from_user.username')
    to_user = serializers.Field(source='to_user.username')

    class Meta:
        model = Message
        fields = ('id', 'status', 'from_user', 'to_user', 'text', 'viewed_on')


# views.py
from permissions import IsOwner

class MessageDetail(generics.RetrieveUpdateDestroyAPIView):
    model = Message
    serializer_class = MessageSerializer
    authentication_classes = (TokenAuthentication, SessionAuthentication)
    permission_classes = (permissions.IsAuthenticated, IsOwner)


# permissions.py
class IsOwner(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit or delete it.
    """

    def has_permission(self, request, view, obj=None):
        # Write permissions are only allowed to the owner of the snippet
        return obj.from_user == request.user


# urls.py
urlpatterns = patterns('',
    url(r'^messages/(?P<pk>[0-9]+)/$', MessageDetail.as_view(), name='api_message_detail'),
)

Then opening the URL of the API i get this error:

**AttributeError at /api/v1/messages/1/
'NoneType' object has no attribute 'from_user'**

Traceback:
File "/var/www/sharigo/python/lib/python2.6/site-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/var/www/sharigo/python/lib/python2.6/site-packages/django/views/generic/base.py" in view
  48.             return self.dispatch(request, *args, **kwargs)
File "/var/www/sharigo/python/lib/python2.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
  77.         return view_func(*args, **kwargs)
File "/var/www/sharigo/python/lib/python2.6/site-packages/rest_framework/views.py" in dispatch
  363.             response = self.handle_exception(exc)
File "/var/www/sharigo/python/lib/python2.6/site-packages/rest_framework/views.py" in dispatch
  351.             self.initial(request, *args, **kwargs)
File "/var/www/sharigo/python/lib/python2.6/site-packages/rest_framework/views.py" in initial
  287.         if not self.has_permission(request):
File "/var/www/sharigo/python/lib/python2.6/site-packages/rest_framework/views.py" in has_permission
  254.             if not permission.has_permission(request, self, obj):
File "/var/www/sharigo/sharigo/apps/sociable/permissions.py" in has_permission
  17.         return obj.from_user == request.user

Exception Type: AttributeError at /api/v1/messages/1/
Exception Value: 'NoneType' object has no attribute 'from_user'

It seems like None is being passed as the value for the parameter "obj" to isOwner.has_permission(). What am I doing wrong? I think i followed strictly the tutorial.

like image 993
nemesisdesign Avatar asked Jan 12 '13 12:01

nemesisdesign


2 Answers

When has_permission() is called with obj=None it's supposed to return whether the user has permission to any object of this type. So you should handle the case when None is passed.

Your code should be something like:

def has_permission(self, request, view, obj=None):
    # Write permissions are only allowed to the owner of the snippet
    return obj is None or obj.from_user == request.user
like image 127
yprez Avatar answered Sep 20 '22 23:09

yprez


Use function has_object_permission instead of has_permission.

ex:

def has_object_permission(self, request, view, obj=None):
    return obj.from_user == request.user

and call function check_object_permissions inside get_object in views

def get_object(self):
    obj = get_object_or_404(self.get_queryset())
    self.check_object_permissions(self.request, obj)
    return obj
like image 20
Amit Avatar answered Sep 21 '22 23:09

Amit