更新时间:2019年10月15日17时07分 来源:传智播客 浏览次数:
在反向解析和命名空间之前我们先来说说URLS硬编码,用django开发应⽤的时候,可以完全是在urls.py中硬编码配置地址,在views.py中HttpResponseRedirect()也是硬编码转向地址,当然在template中也是一样了,这样带来一个问题,如果在urls.py中修改了某个页面的地址(也就是说更改路由系统中对应的路由分发),那么所有的地方(views.py和template中)都要修改。问题出在硬编码,紧耦合使得在大量的模板中修改URLS成为富有挑战性的项目。来看下面的模板文件index.html中,我们到的链接硬编码成这样:
<li><a href="/goods/index/">url硬编码</a></li>
如果使用软编码之后,无论怎么更改路由系统中的路由分发,只有对应的namespace与name属性值不变,就不必修改在views.py和template中的url,也就是说
在使用Django项目时,一个常见的需求是获得URL的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。 人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf毫不相关的专门的URL生成机制,因为这样容易导致一定程度上产生过期的URL。【推荐了解:python+人工智能课程】
获取一个URL最开始想到的信息是处理它视图的标识(例如名字),查找正确的URL的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。Django提供一个办法是让URL映射是URL设计唯一的地方。你填充你的URLconf,然后可以双向使用它:
(1)根据用户/浏览器器发起的URL 请求,它调⽤用正确的Django 视图,并从URL 中提取它的参数需要的值。
(2)根据Django视图的标识和将要传递给它的参数的值,获取与之关联的URL。
第一种方式是我们常说的根据地址定位URL。
第二种方式叫做反向解析URL、反向URL 匹配、反向URL查询或者简单的URL反查。在需要URL的地方。
对于不同层级,Django提供不同的工具用于URL 反查:
(1)在模板中:使⽤用url模板标签。
(2)在Python代码中:使⽤django.core.urlresolvers.reverse() 函数。
(3)在更高层的与处理Django模型实例相关的代码中:使用get_absolute_url()方法。
1、命名空间:
URL命名空间允许你反查到唯一的命名URL模式,即使不同的应用使用相同的URL 名称。第三方应用始终使用带命名空间的URL 是一个很好的实践。类似地,它还允许你在一个应用有多个实例部署的情况下反查URL。换句话讲,因为一个应用的多个实例共享相同的命名URL,命名空间将提供一种区分这些命名URL 的方法。一个URL命名空间有两个部分,它们都是字符串:
<1>应用命名空间:
它表示正在部署的应用的名称。一个应用的每个实例例具有相同的应用命名空间。例如,可以预见Django的管理站点的应⽤命名空间是'admin '。
<2>实例命名空间:
它表示应用的一个特定的实例。实例的命名空间在你的全部项目中应该是唯一的。但是,一个实例的命名空间可以和应用的命名空间相同。它用于表示一个应用的默认实例。例如,Django管理站点实例具有一个默认的实例命名空间'admin'。URL的命名空间使用':'操作符指定。例如,管理站点应用的主页使用'admin:index'。它表示'admin'的一个命名空间和'index'的一个命名URL。
# include函数的APIinclude(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 ininclude() without providing an app_name is not supported. Set the app_nameattribute 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 urlfrom . import viewsapp_name = 'users'# users为当前应⽤用的名称urlpatterns = [url('^$', views.index),url('^(\d+)/$', views.detail),]
三、url反向解析实例
在我们的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
1、路由分发:
daily_fresh_demo/daily_fresh_demo/urls.pyfrom django.contrib import adminfrom django.urls import path
from django.conf.urls import url, includeurlpatterns = [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中。并添加实例命名空间
2、子路由
daily_fresh_demo/df_goods/urls.pyfrom django.conf.urls import urlfrom . import viewsapp_name = 'df_goods' # 应⽤用命名空间urlpatterns = [url('^index/$', views.index, name="index"),]
df_goods中的路由,添加应⽤命名空间。并在url函数中添加name属性。
3、视图函数
daily_fresh_demo/df_goods/views.pyfrom django.shortcuts import render, reversedef index(request):print(reverse("df_goods:index")) # 利利⽤用reverse函数反向解析url# 打印结果为/goods/index/return render(request, 'index.html')
4、静态文件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>
5、结果
静态文件中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地址,不仅耗费时间,更容易产生错误。