Django REST framework: help on object level permission
Question: 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.


Answer: 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
    

