如何在django中编写自定义装饰器?

时间:2011-03-29 07:23:28

标签: python django permissions decorator

问题 -

@is_premium_user
def sample_view:
          .......
          ......

我希望只有网站的高级用户才能访问某些视图 如何在我的项目中的各种应用程序中使用此装饰器?

6 个答案:

答案 0 :(得分:48)

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

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

如果你真的想写自己的装饰,那么网上有很多good documentation

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

答案 1 :(得分:48)

使用上面的各种链接并且无法使它们正常工作然后遇到了我改编的这个非常简单的链接。 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 更好比手动覆盖更像<{1}}。除此之外,它还确保您的包装函数与包装函数具有相同的名称。

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

答案 2 :(得分:5)

感谢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):
    ...

答案 3 :(得分:2)

参见django本身的例子:

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

您的特定示例可能只是'user_passes_test'的一个版本,其中测试将成为'高级'组的成员。

要在任何地方使用,请创建一个python包并从那里导入它。只要它在你的sys.path上它就会被找到。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

这里的实现略有不同,它允许使用其他参数来指定验证失败时重定向到的页面以及向最终用户显示的消息:

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/和以前的答案