是否可以使用 login_required 在 django url 中装饰 include(...)? [英] Is it possible to decorate include(...) in django urls with login_required?
问题描述
我在网站上有一些限制区域,我想为其指定 login_required
装饰器.但是,我想在主 urls.py 中每次包含时执行一次,而不是包含 urls.py 中的每个单独 url
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
所以代替:
/private/urls.py:
/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.
cotton 的第一个片段替换了 RegexURLPattern
和 RegexURLResolver
带有在 resolve
调用期间注入给定装饰器的自定义实现.
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
你需要像这样使用它:
urlpatterns = patterns('',
# ...
(r'^private/', decorated_includes(login_required, include(private.urls))),
)
(注意include
参数不能是这个方法的字符串.)
(Note that include
parameter can't be a string with this method.)
sjzabel 的另一个解决方案,我最终自己使用了,在外面 patterns
调用,因此它可以与字符串一起使用,并且语法略有不同.不过这个想法是一样的.
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
这样称呼它:
urlpatterns = patterns('',
# ...
)
urlpatterns += required(
login_required,
patterns('',
(r'^private/', include('private.urls'))
)
)
两者都很好,但我更喜欢后一种语法.
Both work fine but I prefer the latter syntax.
这篇关于是否可以使用 login_required 在 django url 中装饰 include(...)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!