在django中,在同一个基于类的视图中使用不同的权限装饰器

时间:2013-04-05 21:41:33

标签: django django-class-based-views

我最近在我的Django应用程序中切换到基于类的视图,并希望尽可能优雅地使用它们。在应用程序中,我有一个评论系统,如果权限匹配,管理员应该能够删除和/或发布/取消发布评论。我为此写了一个RedirectView,包括两个功能:

class CommentChangeView(RedirectView, SingleObjectMixin):
    """
    A redirection that acts on a Comment. The url parameter
    "action" is taken as a class function and executed.
    """

    model = Comment


    def get_redirect_url(self, pk):
        """
        Redirect to the article page, always.
        """
        return reverse('post', args=(self.object.post.slug,))


    def get(self, *args, **kwargs):
        """
        Here, it is decided what to execute.
        """

        self.object = self.get_object()
        func = getattr(self, kwargs.pop('action', None), None)

        if callable(func):
            func()

        return super(CommentChangeView, self).get(*args, **kwargs)

    @method_decorator(permission_required('blog.delete_comment'))
    def delete(self):
        """
        Delete the comment
        """

        self.object.delete()
        messages.success(self.request, 'Comment deleted.')

    @method_decorator(permission_required('blog.change_comment'))
    def toggle_publish(self):
        """
        Toggle its publication state
        """

        self.object.published = not self.object.published
        self.object.save()
        messages.success(self.request, 'Comment toggled.')

现在问题是,我希望这两个动作具有不同的权限 - 因此不同的装饰器。通常,dispatch函数会被修饰。上面的代码不起作用,我得到TypeError。没有装饰器,它完美地工作。

我将如何实施此案例?或者我应该将视图分开删除和发布?


以下是TypeError

的StackTrace
Internal Server Error: /comment/toggle_publish/1/
Traceback (most recent call last):
  File "/***/lib/python2.7/site-packages/django/core/handlers/base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/***/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/***/lib/python2.7/site-packages/django/views/generic/base.py", line 86, in dispatch
    return handler(request, *args, **kwargs)
  File "/***/blog/blog/views.py", line 186, in get
    func()
  File "/***/lib/python2.7/site-packages/django/utils/decorators.py", line 25, in _wrapper
    return bound_func(*args, **kwargs)
TypeError: _wrapped_view() takes at least 1 argument (0 given)

1 个答案:

答案 0 :(得分:0)

Bibhas通过更仔细地观察StackTrace,向我指出了正确的方向。通过为函数引入一个额外的参数,我能够使它工作。此代码现在可以使用:

class CommentChangeView(RedirectView, SingleObjectMixin):
    """
    A redirection that acts on a Comment. The url parameter
    "action" is taken as a class function and executed. It therefore
    combines the delete and publish_comment functions (and, later, possibly)
    more.
    """

    model = Comment


    def get_redirect_url(self, pk):
        """
        Redirect to the article page, always.
        """
        return reverse('post', args=(self.object.post.slug,))


    def get(self, request, *args, **kwargs):
        """
        Here, it is decided what to execute.
        """

        self.object = self.get_object()
        func = getattr(self, kwargs.pop('action', None), None)

        if callable(func):
            func(request)

        return super(CommentChangeView, self).get(request, *args, **kwargs)

    @method_decorator(permission_required('blog.delete_comment'))
    def delete(self, request):
        """
        Delete the comment
        """

        self.object.delete()
        messages.success(self.request, 'Comment deleted.')

    @method_decorator(permission_required('blog.change_comment'))
    def toggle_publish(self, request):
        """
        Toggle its publication state
        """

        self.object.published = not self.object.published
        self.object.save()
        messages.success(self.request, 'Comment toggled.')