django2.X 路由兼容 include模块书写规范
使用以往框架的项目路由urls文件
urlpatterns = [ url(r'^user/',include('user.urls', namespace='user')), url(r'^',include('goods.urls',namespace='goods')), ]
报错, 错误信息:
Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
解决方法:
分别单独设置url路由文件路径, app_name应用名称 以及 namespace名称空间.
格式如下:
urlpatterns = [ url(r'^user/',include(('user.urls', 'user'), namespace='user')), url(r'^',include(('goods.urls', 'goods'), namespace='goods')), ]
或者
设置应用url路由文件路径和 app_name. 没有设置的namespace与app_name属性同名.
格式一如下:(需要在应用url路由文件中添加变量 app_name=['应用名'] )
urlpatterns = [ url(r'^user/',include('user.urls')), url(r'^',include('goods.urls')), ]
格式二如下:
urlpatterns = [
url(r'^user/',include(('user.urls', 'user'), )),
url(r'^',include(('goods.urls', 'goods'), )),
]
其中app_name属性可以通过include传入, 也可以单独设置在每个应用url路由文件中. 请根据解耦需要自行选择.
----------------------------------------
原因分析
查看源代码
可得知:
django2.X中, 在include模块里, 重新规定了输入规范,app_name应用名称必须填写.
include要求的三个参数:
urlconf_module,url文件路径
app_name,包名
namespace,命名空间
书写格式为:
include((urlconf_module,app_name),namespace)
urlconf_module,app_name包含在第一个参数的元组中, 第二参数namespace则应是字符串
三个属性中:
urlconf_module和app_name必须传入,app_name可以在父url文件传入也可在子url文件单独定义.
namespace, 可传可不传.
不可以只传入namespace!
源码片段:
def include(arg, namespace=None, app_name=None): if app_name and not namespace: raise ValueError('Must specify a namespace if specifying app_name.') if isinstance(arg, tuple): # callable returning a namespace hint if namespace: raise ImproperlyConfigured('Cannot override the namespace for a dynamic module that provides a namespace') urlconf_module, app_name, namespace = arg else: # No namespace hint - use manually provided namespace urlconf_module = arg if isinstance(urlconf_module, six.string_types): urlconf_module = import_module(urlconf_module) patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module) # Make sure we can iterate through the patterns (without this, some # testcases will break). if isinstance(patterns, (list, tuple)): for url_pattern in patterns: # Test if the LocaleRegexURLResolver is used within the include; # this should throw an error since this is not allowed! if isinstance(url_pattern, LocaleRegexURLResolver): raise ImproperlyConfigured( 'Using i18n_patterns in an included URLconf is not allowed.') return (urlconf_module, app_name, namespace)
def include(arg, namespace=None): app_name = None if isinstance(arg, tuple): # Callable returning a namespace hint. try: urlconf_module, app_name = arg except ValueError: if namespace: raise ImproperlyConfigured( 'Cannot override the namespace for a dynamic module that ' 'provides a namespace.' ) raise ImproperlyConfigured( 'Passing a %d-tuple to include() is not supported. Pass a ' '2-tuple containing the list of patterns and app_name, and ' 'provide the namespace argument to include() instead.' % len(arg) ) else: # No namespace hint - use manually provided namespace. urlconf_module = arg if isinstance(urlconf_module, str): urlconf_module = import_module(urlconf_module) patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module) app_name = getattr(urlconf_module, 'app_name', app_name) if namespace and not app_name: raise ImproperlyConfigured( 'Specifying a namespace in include() without providing an app_name ' 'is not supported. Set the app_name attribute in the included ' 'module, or pass a 2-tuple containing the list of patterns and ' 'app_name instead.', ) namespace = namespace or app_name # Make sure the patterns can be iterated through (without this, some # testcases will break). if isinstance(patterns, (list, tuple)): for url_pattern in patterns: pattern = getattr(url_pattern, 'pattern', None) if isinstance(pattern, LocalePrefixPattern): raise ImproperlyConfigured( 'Using i18n_patterns in an included URLconf is not allowed.' ) return (urlconf_module, app_name, namespace)