Django:DRY原则和UserPassesTestMixin

ggl*_*ses 5 python generics django

我有一个名为的模型,Post并有一个字段owner(外键User).当然,只有业主可以update或delete自己的帖子.

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

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

将对update和delete视图进行此验证.干,这是怎么回事?我应该创建一个名为的类TestUserOwnerOfPost并创建一个test_func(),然后让它update和delete视图继承吗?

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

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)
Run Code Online (Sandbox Code Playgroud)

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

Ala*_*air 7

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

但是,修复不能解决问题,因为UserPassesTestmixin 在运行视图之前执行测试.这意味着它不适合检查所有者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
Run Code Online (Sandbox Code Playgroud)

另一种方法是覆盖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
Run Code Online (Sandbox Code Playgroud)