是否可以使用login_required在django urls中装饰include(...)? [英] Is it possible to decorate include(...) in django urls with login_required?

查看:99
本文介绍了是否可以使用login_required在django urls中装饰include(...)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在网站上有几个限制区域,我想为此指定 login_required 装饰器。但是,我希望这样做一次包含在主要的urls.py中,而不是每个url中包含的urls.py



所以而不是:



/private/urls.py:

 (r'^ profile / $',login_required (个人资料)),

我会做一些事情:



/urls.py

  urlpatterns = patterns('',
...
(r'^ private /',login_required(include('private'))),

不幸的是,它不起作用。

解决方案

这是可行的,其实我刚刚找到两个 片段



解决方案#1



第一个片段由棉花替代 RegexURLPattern RegexURLResolver 与自定义实现在解决调用期间注入装饰器。

  from django.core.urlresolvers导入RegexURLPattern,RegexURLResolver 
from django.conf.urls.defaults import patterns,url,include
from django.contrib import admin
from myproject.myapp.decorators import superuser_required

class DecoratedURLPattern(RegexURLPattern):
def resolve(self,* args,** kwargs):
result = super(DecoratedURLPattern,self).resolve(* args,** kwargs)
如果结果:
result.func = self._decorate_with(result.func)
返回结果

类DecoratedRegexURLResolver(RegexURLResolver):
def resolve(self,* args,** kwargs):
resul t = super(DecoratedRegexURLResolver,self).resolve(* args,** kwargs)
if result:
result.func = self._decorate_with(result.func)
return result

def decorated_includes(func,includes,* args,** kwargs):
urlconf_module,app_name,namespace = includes

for urlconf_module中的项目:
if isinstance (item,RegexURLPattern):
item .__ class__ = DecoratedURLPattern
item._decorate_with = func

elif isinstance(item,RegexURLResolver):
item .__ class__ = DecoratedRegexURLResolver
item._decorate_with = func

返回urlconf_module,app_name,命名空间

你需要这样使用:

  urlpatterns = patterns('',
#...
(r'^ private /',decorated_includes(login_required,include(private.urls))),

(注意 include 参数不能是使用此方法的字符串。)



解决方案#2



我最后使用我的 sjzabel 的另一个解决方案是应用于em>外部 模式调用,因此它可以与字符串一起使用,并且语法略有不同。这个想法是一样的。

  def required(wrapped_functions,patterns_rslt):
'''
用于在url树返回的任何视图中要求1..n装饰器

用法:
urlpatterns =必需(func,patterns(...))
urlpatterns =需要((func,func,func),pattern(...))

注意:
使用functools.partial将关键字参数传递到所需的
装饰器。如果您需要传递参数,则必须编写
包装函数。

示例:
从functools import partial

urlpatterns =必需(
partial(login_required,login_url ='/ accounts / login /'),
模式(...)

'''
如果不是hasattr(wrapped_functions,'__ iter__'):
wrapped_functions =(wrapped_functions,)

return [
_wrap_instance__resolve(wrapped_functions,instance)
,例如pattern_rslt
]

def _wrap_instance__resolve(wrapped_functions,instance):
if不是hasattr(instance,'resolve'):return instance
resolve = getattr(instance,'resolve')

def _wrap_func_in_returned_resolver_match(* args,** kwargs):
rslt = resolve(* args,** kwargs)

如果不是hasattr(rslt,'func'):return rslt
f = getattr(rslt,'func')

for _f in revers(wrapped_function):
#@decorate函数从内到外
f = _f(f)

setattr(rslt,'func',f)

return rslt

setattr(instance,'resolve',_ wrap_func_in_returned_resolver_match)

return instance

它像这样:

  urlpatterns = patterns('',
#...


urlpatterns + =必需(
login_required,
模式('',
(r'^ private /',include('private.urls'))


两者都可以正常工作,但我更喜欢后一种语法。

I have a few restricted areas on the site, for which I would like to specify login_required decorator. However I would like to do that once per inclusion in main urls.py, not per individual url in included urls.py

So instead of:

/private/urls.py:

(r'^profile/$', login_required(profile)),

I'd do something along the lines:

/urls.py

urlpatterns = patterns('',
                      ...
                      (r'^private/', login_required(include('private'))),
                      )

Except that it doesn't work, unfortunately.

解决方案

It is doable, and in fact I just found two snippets for this.

Solution #1

The first snippet by cotton substitutes RegexURLPattern and RegexURLResolver with custom implementations that inject given decorator during resolve call.

from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
from django.conf.urls.defaults import patterns, url, include
from django.contrib import admin
from myproject.myapp.decorators import superuser_required

class DecoratedURLPattern(RegexURLPattern):
    def resolve(self, *args, **kwargs):
        result = super(DecoratedURLPattern, self).resolve(*args, **kwargs)
        if result:
            result.func = self._decorate_with(result.func)
        return result

class DecoratedRegexURLResolver(RegexURLResolver):
    def resolve(self, *args, **kwargs):
        result = super(DecoratedRegexURLResolver, self).resolve(*args, **kwargs)
        if result:
            result.func = self._decorate_with(result.func)
        return result

def decorated_includes(func, includes, *args, **kwargs):
    urlconf_module, app_name, namespace = includes

    for item in urlconf_module:
        if isinstance(item, RegexURLPattern):
            item.__class__ = DecoratedURLPattern
            item._decorate_with = func

        elif isinstance(item, RegexURLResolver):
            item.__class__ = DecoratedRegexURLResolver
            item._decorate_with = func

    return urlconf_module, app_name, namespace

You need to use it like this:

urlpatterns = patterns('',
    # ...
    (r'^private/', decorated_includes(login_required, include(private.urls))),
)

(Note that include parameter can't be a string with this method.)

Solution #2

Another solution by sjzabel, which I ended up using myself, is applied outside patterns call so it can be used with strings and has a slightly different syntax. The idea is the same, though.

def required(wrapping_functions,patterns_rslt):
    '''
    Used to require 1..n decorators in any view returned by a url tree

    Usage:
      urlpatterns = required(func,patterns(...))
      urlpatterns = required((func,func,func),patterns(...))

    Note:
      Use functools.partial to pass keyword params to the required 
      decorators. If you need to pass args you will have to write a 
      wrapper function.

    Example:
      from functools import partial

      urlpatterns = required(
          partial(login_required,login_url='/accounts/login/'),
          patterns(...)
      )
    '''
    if not hasattr(wrapping_functions,'__iter__'): 
        wrapping_functions = (wrapping_functions,)

    return [
        _wrap_instance__resolve(wrapping_functions,instance)
        for instance in patterns_rslt
    ]

def _wrap_instance__resolve(wrapping_functions,instance):
    if not hasattr(instance,'resolve'): return instance
    resolve = getattr(instance,'resolve')

    def _wrap_func_in_returned_resolver_match(*args,**kwargs):
        rslt = resolve(*args,**kwargs)

        if not hasattr(rslt,'func'):return rslt
        f = getattr(rslt,'func')

        for _f in reversed(wrapping_functions):
            # @decorate the function from inner to outter
            f = _f(f)

        setattr(rslt,'func',f)

        return rslt

    setattr(instance,'resolve',_wrap_func_in_returned_resolver_match)

    return instance

Call it like this:

urlpatterns = patterns('',
    # ...
)

urlpatterns += required(
    login_required,
    patterns('',
        (r'^private/', include('private.urls'))
    )
)

Both work fine but I prefer the latter syntax.

这篇关于是否可以使用login_required在django urls中装饰include(...)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆