【问题标题】:How to write a custom decorator in django?如何在 django 中编写自定义装饰器?
【发布时间】:2011-07-25 01:25:19
【问题描述】:

问题-

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

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

【问题讨论】:

    标签: python django permissions decorator


    【解决方案1】:

    玩弄了上面的各种链接,但无法让它们工作,然后遇到了我改编的这个非常简单的链接。 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

    【讨论】:

    • 这应该是公认的答案,竖起大拇指!我试图背负 user_passes_test 装饰器但迷路了,这节省了一天。
    • @radtek 我得到了wrap() takes at least 1 argument (0 given)。有什么线索可以解决吗?
    • 必须查看您的代码,但很可能您没有将请求传递给您正在装饰的函数。
    • @wraps 方法仅适用于文档,因此您可以省略它,对吧?
    【解决方案2】:

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

    还有一个 sn-p (group_required_decorator) 扩展了这个装饰器,它应该非常适合您的用例。

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

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

    【讨论】:

    • def souk_required(): """要求用户至少是传入的组之一。""" def has_souk(u): if u.is_authenticated(): if bool(SoukUsers. objects.get(person = u)): return True return False(u) return user_passes_test(has_souk)
    • 它给出了这个错误 - souk_required 没有参数(1个给定)
    • Hm .. 我不小心点赞了您的评论 ;-) 好吧,您从函数定义中删除了预期的参数,因此收到了给定的错误。那么,如何创建一个组“premiumusers”并将您的用户添加到该组?然后你可以直接使用 sn-p 并传入你的组名。
    • 发生在我们最好的人身上不是你的错; ]....无论如何,非常感谢...我欠你很多时间。
    【解决方案3】:

    感谢arie,这个答案帮了我很大的忙,但它对我不起作用。

    当我找到这个 sn-p 时,我让它正常工作: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):
        ...
    

    【讨论】:

      【解决方案4】:

      查看 django 本身的示例:

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

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

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

      【讨论】:

        【解决方案5】:

        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
        

        【讨论】:

        【解决方案6】:

        这是一个稍微不同的实现,它允许附加参数以指定在验证失败时重定向到哪个页面,以及向最终用户显示哪个消息:

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

        【讨论】:

          猜你喜欢
          • 2018-12-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-07
          • 1970-01-01
          • 1970-01-01
          • 2013-02-06
          • 1970-01-01
          相关资源
          最近更新 更多