Django:DRY原则和UserPassesTestMixin

时间:2016-07-23 17:35:21

标签: python django generics

我有一个名为Post的模型,其中有一个名为owner的字段(User的外键)。当然,只有所有者可以updatedelete发布自己的帖子。

话虽如此,我在视图中使用login_required装饰器以确保用户已登录但是,我还需要确保用户尝试update / delete问题是owner

当我使用Django: Generic Editing Views时,文档说我需要使用Django: UserPassesTestMixin

此验证将针对updatedelete观看次数进行。干,这是怎么回事?我应该创建一个名为TestUserOwnerOfPost的类并创建一个test_func(),然后让updatedelete个视图继承吗?

因为这是我尝试过但没有用的,代码如下:

from django.views.generic.edit import UpdateView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import UserPassesTestMixin

class TestUserOwnerOfPost(UserPassesTestMixin):                         
    def test_func(self):                                                       
        return self.request.user == self.post.owner

class EditPost(UpdateView, TestUserOwnerOfPost):                         
    model = Post                                                                         
    @method_decorator(login_required)                                          
    def dispatch(self, *args, **kwargs):                                       
        return super(EditPost, self).dispatch(*args, **kwargs)

使用上面的代码,系统中的每个登录用户都可以edit / delete发布任何帖子。我究竟做错了什么?我错过了什么吗?感谢。

2 个答案:

答案 0 :(得分:7)

第一个问题是你继承的类的顺序是不正确的,正如@rafalmp所说。

但是,修复并不能解决问题,因为UserPassesTest mixin在运行视图之前执行测试。这意味着它不适合检查self.object的所有者,因为尚未设置self.object。请注意,我使用的是self.object而不是self.post - 我认为视图不会设置self.post,但我可能错了。

一种选择是在测试功能中调用self.get_object()。这有点低效,因为您的视图将获取对象两次,但在实践中它可能无关紧要。

def test_func(self):
    self.object = self.get_object()
    return self.request.user == self.object.owner

另一种方法是覆盖get_queryset,将其限制为用户拥有的对象。这意味着如果用户不拥有该对象,则会收到404错误。此行为与UserPassesTestMixin不完全相同,class OwnerQuerysetMixin(object): def get_queryset(self): queryset = super(OwnerQuerysetMixin, self).get_queryset() # perhaps handle the case where user is not authenticated queryset = queryset.filter(owner=self.request.user) return queryset 将重定向到登录页面,但它可能适合您。

arguments

答案 1 :(得分:2)

您从重要事项继承的类的顺序。要使您的访问控制正常工作,必须在执行UpdateView之前强制执行:

class EditPost(TestUserOwnerOfPost, UpdateView):