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

75 投票
8 回答
84323 浏览
提问于 2025-04-16 14:37

我正在尝试在Django中创建一个自定义装饰器,但我找不到任何方法来实现。

# "views.py"

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

那么,我该如何在Django中创建这个装饰器呢?我应该把它放在哪里,这样我才能在我的Django项目的任何地方使用它呢?

8 个回答

6

感谢arie,这个答案帮了我很多,但对我来说并不管用。

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

这个解决方案对我有效:

辅助函数

这个函数的好处是可以在其他地方重复使用,可以替代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):
    ...
88

我试了上面提到的各种链接,但都没能成功,后来发现了一个非常简单的例子,我做了一些调整。 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

62

你不需要自己写一个装饰器,因为 user_passes_test 已经在Django里提供了。

而且还有一个代码片段 (group_required_decorator),它是对这个装饰器的扩展,应该很适合你的需求。

如果你真的想自己写一个装饰器,网上有很多不错的文档可以参考。

要使用这个装饰器,只需把你的装饰器放在一个模块里,并确保这个模块在你的路径中,这样你就可以从其他模块导入它。

撰写回答