我有一个名为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)
使用上面的代码,系统中的每个登录用户都可以edit
/ delete
发布任何帖子。我究竟做错了什么?我错过了什么吗?感谢。
答案 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):