在反向解析和命名空间以前咱们先来讲说URLS硬编码,用django 开发应用的时候,能够彻底是在urls.py 中硬编码配置地址,在views.py中HttpResponseRedirect()也是硬编码转向地址,固然在template 中也是同样了,这样带来一个问题,若是在urls.py 中修改了某个页面的地址(也就是说更改路由系统中对应的路由分发),那么全部的地方(views.py和template中)都要修改。问题出在硬编码,紧耦合使得在大量的模板中修改 URLs 成为富有挑战性的项目。来看下面的模板文件index.html中,咱们到的连接硬编码成这样子:html
<li><a href="/goods/index/">url硬编码</a></li>
若是使用软编码以后,不管怎么更改路由系统中的路由分发,只有对应的namespace与name属性值不变,就没必要修改在views.py和template中的url,也就是说django
<li><a href="{% url "good:index" %}">url软编码</a></li>
在templates中更改成软编码以后,其实在templates,index.html文件生成的时候,仍然是浏览器
<li><a href="/goods/index/">url软编码</a></li>
在使用Django 项目时,一个常见的需求是得到URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
人们强烈但愿不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 绝不相关的专门的URL 生成机制,由于这样容易致使必定程度上产生过时的URL。 服务器
获取一个URL 最开始想到的信息是处理它视图的标识(例如名字),查找正确的URL 的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。
Django 提供一个办法是让URL 映射是URL 设计惟一的地方。你填充你的URLconf,而后能够双向使用它:
一、根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数须要的值。
二、根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。app
第一种方式是咱们常说的根据地址定位URL。函数
第二种方式叫作反向解析URL、反向URL 匹配、反向URL 查询或者简单的URL 反查。工具
在须要URL 的地方,对于不一样层级,Django 提供不一样的工具用于URL 反查:
一、在模板中:使用url 模板标签。
二、在Python 代码中:使用 django.core.urlresolvers.reverse() 函数。
三、在更高层的与处理Django 模型实例相关的代码中:使用 get_absolute_url() 方法。
编码
URL 命名空间容许你反查到惟一的命名URL 模式,即便不一样的应用使用相同的URL 名称。第三方应用始终使用带命名空间的URL 是一个很好的实践。相似地,它还容许你在一个应用有多个实例部署的状况下反查URL。换句话讲,由于一个应用的多个实例共享相同的命名URL,命名空间将提供一种区分这些命名URL 的方法。url
一个URL 命名空间有两个部分,它们都是字符串:spa
它表示正在部署的应用的名称。一个应用的每一个实例具备相同的应用命名空间。例如,能够预见Django 的管理站点的应用命名空间是' admin '。
它表示应用的一个特定的实例。实例的命名空间在你的所有项目中应该是惟一的。可是,一个实例的命名空间能够和应用的命名空间相同。它用于表示一个应用的默认实例。例如,Django 管理站点实例具备一个默认的实例命名空间'admin'。 URL的命名空间使用':' 操做符指定。例如,管理站点应用的主页使用' admin:index '。它表示' admin ' 的一个命名空间和' index ' 的一个命名URL.
# include函数的API include(arg, namespace=None, app_name=None) # namespace设置实例命名空间,app_name设置应用命名空间 # 不能只设置app_name,不然会报错,如下是报错的源码 if app_name and not namespace: raise ValueError('Must specify a namespace if specifying app_name.')
通常来讲,同一应用下的不一样实例应该具备相同的应用命名空间,可是,这并不意味着不一样应用可使用相同的实例命名空间,由于实例命名空间在你全部项目中都是惟一的。
问题: 另外在添加命名空间 namespace时可能会出现如下这个问题:
'Specifying a namespace in include() without providing an app_name ' django.core.exceptions.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.
解决方案为:
在对应的app应用的urls.py中添加app_name = '[应用名称]'以下
from django.conf.urls import url from . import views app_name = 'users' # users为当前应用的名称 urlpatterns = [ url('^$', views.index), url('^(\d+)/$', views.detail), ]
在咱们的django项目中一般App,目录结构就能够以下daily_fresh_demo
daily_fresh_demo
|----daily_fresh_demo |----__init__.py |----settings.py |----urls.py |----wsgi.py |----df_cart #对商品购物车管理 |---- migrations # 迁移文件目录 |---- admin.py |---- apps.py |---- models.py |---- test.py |---- urls.py |---- views.py |---- __init__.py |----df_goods #商品以及后台管理 ... |----df_user #用户管理 ... |----df_order #订单管理 ...
|----templates
|index.html
daily_fresh_demo/daily_fresh_demo/urls.py
from django.contrib import admin from django.urls import path from django.conf.urls import url, include urlpatterns = [ path('admin/', admin.site.urls), url(r'^goods/', include('df_goods.urls', namespace='df_goods')), # 添加实例命名空间 url(r'^user/', include('df_user.urls', namespace='df_user')), url(r'^cart/', include('df_cart.urls', namespace='df_cart')), url(r'^order/', include('df_order.urls', namespace='df_order')), ]
根据路由分发到各个相应的app中。并添加实例命名空间
daily_fresh_demo/df_goods/urls.py
from django.conf.urls import url from . import views app_name = 'df_goods' # 应用命名空间 urlpatterns = [ url('^index/$', views.index, name="index"), ]
df_goods中的路由,添加应用命名空间。并在url函数中添加name属性。
三、视图函数
daily_fresh_demo/df_goods/views.py from django.shortcuts import render, reverse def index(request): print(reverse("df_goods:index")) # 利用reverse函数反向解析url
# 打印结果为/goods/index/
return render(request, 'index.html')
四、静态文件 index.html
daily_fresh_demo/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<a href="/goods/index">硬连接</a>
<a href="{% url "df_goods:index" %}">软连接</a>
</body>
</html>
五、结果
静态文件中index.html的url解析结果以下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <a href="/goods/index">硬连接</a> <a href="/goods/index/">软连接</a> # 软编码经过解析后获得的结果与硬编码一致 </body> </html>
总结:这样一来经过命名空间,不管在templates文件中有多庞大的url地址映射,只要使用url软编码,在更改路由系统的时候,都能自动生成。而若是使用硬连接硬编码 ,就只能在views.py和静态文件中逐个修改url地址,不只耗费时间,更容易产生错误。