如何在 Django 中创建自定义装饰器?

我试图在 Django 中创建一个定制的装饰器,但我找不到任何方法来做到这一点。

# "views.py"


@custom_decorator
def my_view(request):
# .......

那么,我如何在 Django 中创建它呢?我应该把它放在哪里,这样我就可以在我的姜戈项目的任何地方使用它?

78381 次浏览

Http://www.makina-corpus.org/blog/permission-required-decorator-django

我是根据那篇博客写的。

将它粘贴到 python 路径或“ util”应用程序的文件中,并将其导入到视图中:

例如

project_dir
|_ app1
|_ app2
|_ utils
|_ __init__.py
|_ permreq.py




from util.permreq import permission_required


@permmission_required('someapp.has_some_perm', template='denied.html')
def some_view(request):
blah blah

您不必为此编写自己的装饰器,因为 Django 中已经包含了 user_passes_test

还有一个代码片段(group_required_decorator)扩展了这个装饰器,它应该非常适合您的用例。

如果你真的想写自己的装饰,那么有很多网上的 良好的文件

要(重新)使用装饰器,只需将装饰器放在路径上的模块中,就可以从任何其他模块导入它。

看看姜戈本身的例子:

Http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/decorators.py

您的特定示例可能只是“ user _ pass _ test”的一个版本,其中的测试将成为“ Premium”组的成员。

要在任何地方使用,可以创建一个 python 包并从中导入它。只要它在你的 sys.path 上,就会被发现。

玩了各种各样的链接以上,无法让他们的工作,然后遇到了这个真正简单的一个,我适应。http://code.activestate.com/recipes/498217-custom-django-login_required-decorator/

from functools import wraps
from django.http import HttpResponseRedirect


def authors_only(function):
@wraps(function)
def wrap(request, *args, **kwargs):


profile = request.user.get_profile()
if profile.usertype == 'Author':
return function(request, *args, **kwargs)
else:
return HttpResponseRedirect('/')


return wrap

使用 @wraps比手动重写 wrap.__doc__ = fn.__doc__要好。除此之外,它还可以确保包装函式与包装函数的名称相同。

参见 https://docs.python.org/2/library/functools.html

多亏了 Arie 答案帮了我大忙,但对我没用。

当我找到这个片段时,我让它正常工作: http://djangosnippets.org/snippets/983/

这个方法对我很有效:

Helper 函数

这个函数的好处是可以在其他地方重用,作为 user.is_authenticated的替代品。例如,它可以公开为一个模板标记。

def my_custom_authenticated(user):
if user:
if user.is_authenticated():
return user.groups.filter(name=settings.MY_CUSTOM_GROUP_NAME).exists()
return False

那个室内设计师

我只是把这个放在我的 views.py的顶部,因为它太短了。

def membership_required(fn=None):
decorator = user_passes_test(my_custom_authenticated)
if fn:
return decorator(fn)
return decorator

用它

@membership_required
def some_view(request):
...

下面是一个略有不同的实现,它允许额外的参数,以指定验证失败时重定向到哪个页面,以及向最终用户显示哪条消息:

from functools import wraps
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from core.helpers.flash import send_flash_error


def lender_only(redirect_to='plateforme.views.vue_login', error_flash_message=None):
def inner_render(fn):
@wraps(fn)  # Ensure the wrapped function keeps the same name as the view
def wrapped(request, *args, **kwargs):
if request.context.user.is_authenticated and request.context.user.is_lender:
return fn(request, *args, **kwargs)
else:
if error_flash_message:
send_flash_error(request, error_flash_message) # Replace by your own implementation


return HttpResponseRedirect(reverse(redirect_to))
return wrapped
return inner_render

# Usage:
@lender_only('vitrine.views.projets', {'message': "Oops, can't go there."})
def render_page_index(request):

这本指南帮助我通过它: https://elfsternberg.com/2009/11/20/python-decorators-with-arguments-with-bonus-django-goodness/与以前的答案

from django.contrib.auth.decorators import user_passes_test
from django.core.exceptions import PermissionDenied


def perm_group_required(group, login_url='/', raise_exception=False):
def check_group(user):
if user.groups.filter(name=group).exists():
return True
# In case the 403 handler should be called raise the exception
if raise_exception:
raise PermissionDenied
return False
return user_passes_test(check_group, login_url=login_url)




@perm_group_required('add_customer_group')
#group name="add_customer_group"
def employee_add_customer(request):
##logic
...

例如,对于下面的 定制的装饰者 @trantest()可以在事务中运行。* 你可以看到 我的回答详细解释了一个定制的装饰器:

# "views.py"


from django.db import transaction
from django.http import HttpResponse


def tran(func): # Here
def core(request, *args, **kwargs):
with transaction.atomic():
return func(request, *args, **kwargs)
return core


@tran # Here
def test(request):
person = Person.objects.all()
print(person)
return HttpResponse("Test")