在网站开发中,最多的元素就是
a
标签了,每个网站都是由不同的链接组合起来,让用户通过点击进入不同的页面进而服务用户的。
在实际的业务开展中,很多URL
的资源标识名并不是一成不变的,而是根据公司业务进行不断的改变,如果页面上的所有a
标签的跳转都是写成字符串常量形式的话,那么如果一旦有一个业务的资源标识发生了改变,那么开发人员将会对所有的页面上的a
标签进行手动修改内容,那简直是无法想象的工作量。
所以,在实际开发中,既然路由能正向指向了视图函数,那么有没有什么方法,能够通过一个标识找到路由信息,答案就是Django的反向路由模块来支持了。
1、反向路由的概念
我们的路由是一个匹配关系,对应一个处理的视图函数,
如果我们的匹配关系发生了变化,那么与之对应的访问地址(可能前端直接url
链接,也可能是后端的redirect
跳转)都需要跟着发生改变这是费时费力,因此我们想到了一种动态解析url
的方法,通过给相应的匹配关系起别名,而让与之对应的链接或者跳转,会根据别名动态解析前面的匹配关系,这个动态解析url
路径的过程就是反向解析。反向路由可以根据别名直接生成对应的url
地址。
2、给url起名字
给url
起名字:name
。起名字用于反向解析。
name
参数可以给这个url
取一个合适的名字。通过给url
取名字,以后在view
或者模板中使用这个URL
,就只需要通过这个名字就可以了。这样做的原因是防止url
的规则更改,会导致其他地方用了这个url
的地方都需要更改,但是如果取名字了,就不用做任何改动了。
给一个匹配的url
地址取名字一般用于模板,也可以使用reverse
进行页面重定向。
path('',views.index,name='index'),
path('<int:x>', views.detail,name='detail'),
re_path(r'^test/(\d+)$',views.newdetail,name='newdetail'),
re_path(r'^(\d+)/(\d+)/(\d+)/$',views.detail3,name='detail3'),
re_path(r'^keyword/(?P<book_id>\d+)$',views.detail4,name='detail4'),
re_path(r'^keyword/(?P<p2>\d+)/(?P<p3>\d+)/(?P<p1>\d+)/$',views.detail3,name='detail5'),
3、命名空间
在不同的业务中,都有一个主页的概念,这样会有一种情况,每个app
的设计者,都命名了一个name=‘index’
的主页路由反向映射标识,那如何区别他们那?
Django
给我们提供了一个叫做名字空间的概念,来区别不同app
的同名标识。
在include
方法内,有一个namespace
的参数,他接收一个字符串作为子路由映射关系的命名空间。
path('study/',include(('apps.study.urls','study'),namespace='study')),
注意:
- 在
include
方法里面指定namespace
却不提供app_name
是不允许的。 - 在包含的模块里设置
app_name
变量,或者在include
方法里面提供app_name
参数。上述代码写在了include
方法中。具体用法如下:
(1)方式一:在include
方法里面提供app_name
参数
(2)方式二:在包含的模块里设置app_name
变量
4、reverse功能
Django
中提供了reverse
函数来完成URL
的反向查找功能,它仍然定义在django.urls
模块中。
这个函数必须传递至少一个参数,这个参数就是url反向查找的标识信息,该信息需要在URL
正向映射中,由程序员手动添加进去才行。
reverse
函数里提供了args
来代表位置参数,kwargs
来代表命名参数。
5、示例——在视图中使用使用反向路由
前提:已经给url
和include
取名。
(1)配置路由
path('reverseTest/',views.reverseTest,name="reverseTest"),
(2)编写视图
def reverseTest(request):
# 后端不带参数反向路由
# path('', views.index, name='index'),
d1 = reverse('study:index')
# 后端位置参数反向路由
# path('<int:x>', views.detail, name='detail'),
# re_path(r'^test/(\d+)$', views.newdetail, name='newdetail'), # r防止字符转义,表示非转义的原始字符
# re_path(r'^(\d+)/(\d+)/(\d+)/$', views.detail3, name='detail3'),
d2 = reverse('study:detail',args=(10,))
d3 = reverse('study:newdetail',args=(112,))
d4 = reverse('study:detail3',args=(100,200,300))
# 后端关键字参数反向路由
# re_path(r'^keyword/(?P<book_id>\d+)$', views.detail4, name='detail4'),
# re_path(r'^keyword/(?P<p2>\d+)/(?P<p3>\d+)/(?P<p1>\d+)/$', views.detail3, name='detail5'),
d5 = reverse('study:detail4',kwargs={'book_id':100})
d6 = reverse('study:detail5',kwargs={'p2':100,'p3':200,'p1':300})
msg = "<h1>后端不带参数反向路由</h1>" + d1 + "<br>"
msg += "<h1>后端位置参数反向路由</h1>" + d2 + "<br>" + d3 + "<br>" + d4 + "<br>"
msg += "<h1>后端关键字参数反向路由</h1>" + d5 + "<br>" + d6
return HttpResponse(msg)
(3)输入http://127.0.0.1:8001/study/reverseTest/
查看效果
6、练习
将视图中使用的硬编码改成反向路由来实现。
path('redTest2/', views.redTest2,name='redTest2'),
return redirect(reverse('study:redTest2'))