Compose 装饰器应用于基于 class 的视图
Compose decorators applied to class-based views
我有权限检查和视图的层次结构,需要由它们来保护。例如,考虑这两项检查。
def has_profile(user):
return user.profile is not None
def is_a_sorcerer(user):
return user.profile.category == 'sorcerer'
请注意,只有在用户有个人资料时调用 is_a_sorcerer
才有意义。
有些观点应该可供任何拥有个人资料的人访问,有些观点进一步仅限于巫师。
class ProfileView(View):
@method_decorator(user_passes_test(has_profile))
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
class SorcererView(ProfileView):
@method_decorator(user_passes_test(is_a_sorcerer))
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
但是,请注意,由于继承,is_a_sorcerer
将在 之前被调用 has_profile
并出错。
可以在 is_a_sorcerer
中检查 has_profile
:
def is_a_sorcerer(user):
return has_profile(user) and user.profile.category == 'sorcerer'
虽然这修复了错误,但会导致检查 has_profile
两次,并且检查超过两层时,开销会迅速累积。
如何在不重复代码的情况下组合这些装饰器?我仍然希望将权限检查保留为函数,以便它们可以应用于基于函数的视图。
实际上,我会简单地检查 is_a_sorcerer
方法中的 has_profile
。检查 has_profile
两次的开销可以忽略不计。
def is_a_sorcerer(user):
return has_profile(user) and user.profile.category == 'sorcerer'
可以避免 运行 检查两次,但我认为您无法使用装饰器。相反,您可以更改 ProfileView
以便它检查测试列表。然后覆盖子类中的测试列表。
class ProfileView(View):
user_tests = [has_profile]
def dispatch(self, *args, **kwargs):
for test_func in self.user_tests:
if not test_func(self.request.user):
return redirect('login')
return super().dispatch(*args, **kwargs)
class SorcererView(ProfileView):
user_tests = ProfileView.user_tests + [is_a_sorcerer]
请注意,这不太传统,而且可能更 fragile/error 容易发生。在子类中覆盖 user_tests
时很容易忘记包含 ProfileView.user_tests
。
我有权限检查和视图的层次结构,需要由它们来保护。例如,考虑这两项检查。
def has_profile(user):
return user.profile is not None
def is_a_sorcerer(user):
return user.profile.category == 'sorcerer'
请注意,只有在用户有个人资料时调用 is_a_sorcerer
才有意义。
有些观点应该可供任何拥有个人资料的人访问,有些观点进一步仅限于巫师。
class ProfileView(View):
@method_decorator(user_passes_test(has_profile))
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
class SorcererView(ProfileView):
@method_decorator(user_passes_test(is_a_sorcerer))
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
但是,请注意,由于继承,is_a_sorcerer
将在 之前被调用 has_profile
并出错。
可以在 is_a_sorcerer
中检查 has_profile
:
def is_a_sorcerer(user):
return has_profile(user) and user.profile.category == 'sorcerer'
虽然这修复了错误,但会导致检查 has_profile
两次,并且检查超过两层时,开销会迅速累积。
如何在不重复代码的情况下组合这些装饰器?我仍然希望将权限检查保留为函数,以便它们可以应用于基于函数的视图。
实际上,我会简单地检查 is_a_sorcerer
方法中的 has_profile
。检查 has_profile
两次的开销可以忽略不计。
def is_a_sorcerer(user):
return has_profile(user) and user.profile.category == 'sorcerer'
可以避免 运行 检查两次,但我认为您无法使用装饰器。相反,您可以更改 ProfileView
以便它检查测试列表。然后覆盖子类中的测试列表。
class ProfileView(View):
user_tests = [has_profile]
def dispatch(self, *args, **kwargs):
for test_func in self.user_tests:
if not test_func(self.request.user):
return redirect('login')
return super().dispatch(*args, **kwargs)
class SorcererView(ProfileView):
user_tests = ProfileView.user_tests + [is_a_sorcerer]
请注意,这不太传统,而且可能更 fragile/error 容易发生。在子类中覆盖 user_tests
时很容易忘记包含 ProfileView.user_tests
。