使用多个UserPassesTestMixin适用于其他视图但不适用于ProfileCreateView
似乎存在一个我无法弄清楚的逻辑错误!
views.py
class CurrentUser(UserPassesTestMixin):
def test_func(self):
x = self.request.user.slug
print (x)
y = self.kwargs['slug']
print (y)
if x == y:
return True
else:
if self.request.user.is_authenticated():
def get_absolute_url(self):
return reverse('profile:view_profile', kwargs={ "slug": self.slug })
class ProfileCreate(CurrentUser, UserPassesTestMixin, LoginRequiredMixin, UpdateView):
model = User
form_class = ProfileForm
template_name="profile/profile_new.html"
def test_func(self):
x = self.get_object().full_name
print (x)
y = ''
if x == y:
return True
else:
def get_absolute_url(self):
return reverse('profile:view_profile', kwargs={ "slug": self.slug })
class ProfileEdit(CurrentUser, UserPassesTestMixin, LoginRequiredMixin, UpdateView):
model = User
form_class = ProfileForm
template_name="profile/profile_new.html"
def test_func(self):
x = self.get_object().full_name
#print (x)
y = ''
if x != y:
return True
else:
def get_absolute_url(self):
return reverse('profile:profile_edit', kwargs={ "slug": self.slug })
班级CurrentUser
检查用户是否具有编辑个人资料的权限。如果用户是个人资料的作者,则用户将只能编辑该个人资料。 x和y都是这个类打印不同的值 x打印登录用户的slug值而 y打印来自url的slug 这怎么可能是真的?
test_func
类中的ProfileCreate
检查用户是否已创建配置文件,即如果full_name
为空字符串,则允许用户创建配置文件。否则重定向到其他视图。
CurrentUser
类适用于其他视图,例如ProfileEdit
等,
摘要! -
loggedin user- localhost:8000/username1
用户将能够访问localhost:8000/username1/edit/
但不能访问localhost:8000/username2/edit/
只有当localhost:8000/username1/create/
为空时,用户才能访问full_name
。
如果用户以username1身份登录,则用户应该无法访问localhost:8000/username2/create/
----这部分代码不起作用。代码中的逻辑错误是什么?
答案 0 :(得分:1)
你不能有两个叫做同一个东西的方法。您在ProfileCreate中的test_func
会覆盖CurrentUser中的{。}}。
答案 1 :(得分:0)
您可以通过对继承使用合成来实现:
class A(UserPassesTestMixin):
def test_func(self):
return True
class B(UserPassesTestMixin):
def test_func(self):
return True
class C(UserPassesTestMixin):
def test_func(self):
return B.test_func(self) and A.test_func(self) and True
如果像我一样,您不喜欢它,则可以进行装饰以处理连词:
def check_all_tests(cls):
tests = []
if issubclass(cls, UserPassesTestMixin):
tests.append(cls.test_func)
for parent in cls.__bases__:
if issubclass(parent, UserPassesTestMixin):
tests.append(parent.test_func)
cls.test_func = lambda view: all(test(view) for test in tests)
return cls
@check_all_tests
class C(A, B, UserPassesTestMixin):
def test_func(self):
return True
并且我喜欢一直进行装饰,所以我做了一个Decoration_builder:
def make_user_test(func):
def wrapper(cls):
if issubclass(cls, UserPassesTestMixin):
old_func = cls.test_func
cls.test_func = lambda view: old_func(view) and func(view)
return cls
else:
new_cls = type(cls.__name__, (UserPassesTestMixin, *cls.__bases__), cls.__dict__.copy())
new_cls.test_func = func
return new_cls
return wrapper
@make_user_test
def is_creator(view):
return view.get_object().created_by == view.request.user
@is_creator
@make_user_test(lambda view: view.get_object() != view.request.user.profile.party) # user cannot delete itself
class PartyDelete(DeleteView):
model = Party
success_url = reverse_lazy('party_list')
如果您想要一些元数据,我做了一个函数,该函数将测试列表(函数)作为参数,并返回一个类装饰,该类装饰通过继承包装了原始对象,并添加了所有测试的并集:
from inspect import isfunction, signature
from functools import wraps
def user_passes_tests(*args):
"""
Creates a class decorator that makes decorated class implement UserPassesTestMixin and
provides implementation using a logical conjunction with all provided functions
Decorated class must NOT implement UserPassesTestMixin itself
"""
assert len(args) > 0, 'Provide at least one argument'
assert all(isfunction(arg) for arg in args), 'All arguments are supposed to be functions'
assert all(len(signature(f).parameters) == 1 for f in args), 'Functions must expect one and only one argument'
def decorator(cls):
assert not issubclass(cls, UserPassesTestMixin), \
"Do not apply this decorator on UserPassesTestMixin subclass"
@wraps(cls, updated=())
class WrapperClass(UserPassesTestMixin, cls):
def test_func(self):
return all(func(self) for func in args)
return WrapperClass
return decorator
@user_passes_tests(is_creator, is_not_party)
class PartyDelete(DeleteView):
model = Party
success_url = reverse_lazy('party_list')