我在网站上有一些限制区域,我想为此指定login_required装饰器。但是我想对每个包含在主urls.py中的对象执行一次操作,而不是对包含在urls.py中的每个单独的URL进行一次操作。
login_required
所以代替:
/private/urls.py:
(r'^profile/$', login_required(profile)),
我会做一些事情:
/urls.py
urlpatterns = patterns('', ... (r'^private/', login_required(include('private'))), )
不幸的是,除了它不起作用。
这是可行的,实际上我为此找到了两个 片段。
解决方案1 棉花替代品的第一个片段,RegexURLPattern以及RegexURLResolver在resolve通话期间注入给定装饰器的自定义实现。
RegexURLPattern
RegexURLResolver在resolve
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此方法不能将参数作为字符串。)
include
解决方案#2 sjzabel的另一个解决方案(我最终使用了我自己)在外部 patterns调用中应用,因此可以与字符串一起使用,并且语法略有不同。但是,想法是一样的。
patterns
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')) ) )
两者都能正常工作,但我更喜欢后一种语法。