Django REST框架:对象级权限帮助

6

按照这个教程:

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

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

我有以下代码:

# 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'),
)

当我打开API的URL时,出现以下错误:

**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'

似乎将None作为参数“obj”的值传递给了isOwner.has_permission()。我做错了什么?我认为我严格遵循了教程。

在DRF 3中,有has_object_permission - http://www.django-rest-framework.org/api-guide/permissions/#custom-permissions - Chemical Programmer
2个回答

9
当调用has_permission()方法并传入参数obj=None时,该方法应返回用户是否拥有访问改类型的任何对象的权限。因此,您需要处理传入参数为None的情况。
您的代码应该如下所示:
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

我被搞糊涂了,因为一开始似乎是大小写导致限制不起作用。谢谢。 - nemesisdesign

9

使用 has_object_permission 函数代替 has_permission

例如:

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

在视图中的 get_object 方法内调用 check_object_permissions 函数。

def get_object(self):
    obj = get_object_or_404(self.get_queryset())
    self.check_object_permissions(self.request, obj)
    return obj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接