Python Django-如何使用两个UserPasseStMixin
使用多个UserPasseTestMixin适用于其他视图,但不适用于Python Django-如何使用两个UserPasseStMixin,python,django,Python,Django,使用多个UserPasseTestMixin适用于其他视图,但不适用于ProfileCreateView 似乎有一个逻辑错误,我无法理解 views.py class CurrentUser(UserPassesTestMixin): def test_func(self): x = self.request.user.slug print (x) y = self.kwargs['slug'] print (y)
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打印loggedin用户的slug值,而y打印url中的slug值这怎么可能是真的
ProfileCreate
类中的test\u func
检查用户是否已经创建了配置文件,即如果full\u name
是空字符串,则允许用户创建配置文件。否则将重定向到其他视图
CurrentUser
类适用于其他视图,如ProfileEdit
等
总结强>--
loggedinuser-localhost:8000/username1
用户将能够访问localhost:8000/username1/edit/
,但不能访问localhost:8000/username2/edit/
只有当全名
为空时,用户才能访问localhost:8000/username1/create/
。
如果用户登录为username1,则该用户应无法访问
localhost:8000/username2/create/
——这部分代码不起作用。代码中的逻辑错误是什么?不能有两个方法调用同一个东西。ProfileCreate中的测试函数将覆盖CurrentUser中的函数。您可以通过使用组合而不是继承来实现这一点:
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
由于我更喜欢一路装饰,我做了一个装饰设计师:
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')
我在ProfileEdit
类中使用相同的方法,效果很好。