我的models.py文件如下:
from django.contrib.auth.models import User
class Shopkeeper(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
# ...
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
# ...
我有一些 View 只有客户在登录后才能访问,但店主不能。反之亦然。 我该如何为这样的任务编写装饰器?
请您参考如下方法:
装饰器并没有什么神奇之处,它是一个函数,它以要装饰的函数(或类)作为输入,并对其进行一些更改。如果我们看一下 login_required decorator [GitHub] ,我们看到:
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None): """ Decorator for views that checks that the user is logged in, redirecting to the log-in page if necessary. """ actual_decorator = user_passes_test( lambda u: u.is_authenticated, login_url=login_url, redirect_field_name=redirect_field_name ) if function: return actual_decorator(function) return actual_decorator
因此,我们实际上可以简单地制作一个 user_passes_test 装饰器的特例:
from django.contrib.auth.decorators import user_passes_test
def shopkeeper_required(function=None):
def is_shopkeeper(u):
return Shopkeeper.objects.filter(user=u).exists()
actual_decorator = user_passes_test(is_shopkeeper)
if function:
return actual_decorator(function)
else:
return actual_decorator
def customer_required(function=None):
def is_customer(u):
return Customer.objects.filter(user=u).exists()
actual_decorator = user_passes_test(is_customer)
if function:
return actual_decorator(function)
else:
return actual_decorator
例如,您可以将其实现为:
@login_required
@shopkeeper_required
def some_shopkeeper_view(request):
# ...
pass
@login_required
@customer_required
def some_customer_view(request):
# ...
pass
请注意,此 @shopkeeper_required 确实不强制用户登录,尽管在许多情况下都是如此。
编辑:
我们可以将它与 @login_required 合并(通过添加一个参数作为开关来打开或关闭此行为,默认情况下打开),例如:
from django.contrib.auth.decorators import user_passes_test
def shopkeeper_required(function=None<b>, login_required=True</b>, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
def is_shopkeeper(u):
<b>if login_required and not u.is_authenticated:
return False</b>
return Shopkeeper.objects.filter(user=u).exists()
actual_decorator = user_passes_test(
is_shopkeeper,
login_url=login_url,
redirect_field_name=redirect_field_name
)
if function:
return actual_decorator(function)
else:
return actual_decorator
def customer_required(function=None<b>, login_required=True</b>, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
def is_customer(u):
<b>if login_required and not u.is_authenticated:
return False</b>
return Customer.objects.filter(user=u).exists()
actual_decorator = user_passes_test(
is_customer,
login_url=login_url,
redirect_field_name=redirect_field_name
)
if function:
return actual_decorator(function)
else:
return actual_decorator
