如何在Django中编写自己的装饰器? [英] How can I write my own decorator in Django?
问题描述
我的 models.py
文件如下:
My models.py
file is as follow:
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)
# ...
我有一些视图,只有客户可以登录后访问,但店主无法访问。反之亦然。
如何为此类任务编写装饰器?
And I have some views which only Customers can access after login, but Shopkeepers cannot. And vice versa. How can I write decorator for such task?
推荐答案
装饰器没有什么神奇之处,它是一个函数将要装饰的函数(或类)作为输入,并对其进行一些更改。如果我们查看 login_required
装饰器[GitHub] ,我们看到:
There is nothing magical about a decorator, it is a function that takes as input the function (or class) to decorate, and makes some changes to it. If we look at the login_required
decorator [GitHub], we see:
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
装饰器的特殊情况:
We can thus actually simply make a special case of the user_passes_test
decorator:
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
不会 确实要求用户登录,尽管在很多情况下都是这样。
Note that this @shopkeeper_required
does not really enforces that the user is logged in, although in many cases that will be the case.
EDIT :
我们可以将其与 @login_required
合并(通过添加一个参数来作为打开或关闭此行为的开关,默认启用),例如:
We can merge this with a @login_required
(by adding a parameter that acts as a switch to turn this behavior on or off, by default on), like:
from django.contrib.auth.decorators import user_passes_test
def shopkeeper_required(function=None, login_required=True, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
def is_shopkeeper(u):
if login_required and not u.is_authenticated:
return False
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, login_required=True, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
def is_customer(u):
if login_required and not u.is_authenticated:
return False
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
这篇关于如何在Django中编写自己的装饰器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!