关于python:Django:DRY原则和UserPassesTestMixin

Django: DRY principle and UserPassesTestMixin

我有一个名为Post的模型,还有一个名为owner的字段(User的外键)。当然,只有拥有者才能拥有自己的职位。

这就是说,我在视图中使用login_required修饰器来确保用户登录,但是,我还需要确保尝试update/delete的用户,问题是owner

当我使用django:generic编辑视图时,文档说我需要使用django:userpassestmixin。

将对updatedelete视图进行验证。干,怎么办?我应该创建一个名为TestUserOwnerOfPost的类,并创建一个test_func(),然后让updatedelete视图继承它吗?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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。我做错什么了?我错过什么了吗?谢谢。


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

但是,解决这一问题并不能解决问题,因为UserPassesTestmixin在运行视图之前执行测试。这意味着,由于self.object尚未设置,因此不适合检查self.object的所有者。注意,我使用的是self.object而不是self.post,我不认为这个视图设置了self.post,但我可能错了。

一种选择是在测试函数内部调用self.get_object()。这有点低效,因为您的视图将获取对象两次,但实际上可能并不重要。

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

另一种方法是重写get_queryset,将其限制为用户拥有的对象。这意味着如果用户不拥有对象,他们将得到404错误。这种行为与UserPassesTestMixin并不完全相同,后者将重定向到登录页面,但对您来说可能没问题。

1
2
3
4
5
6
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


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

1
class EditPost(TestUserOwnerOfPost, UpdateView):