Django学习笔记〇九——路由系统
我们在前面讲了Django的第一个部分——视图系统,今天来看看第二个部分:路由系统。
简而言之,Django的路由系统就是建立视图views里和请求的url之间的映射关系。在请求到来之后,根据urls.py中的关系条目,查找相应的处理方法,从而返回给用户所需要的html页面。
我们前面的几个项目案例中,用到的都是这种最基础的映射关系:
只有一个App
只有一级路由
路由里的url写的都是简单的正则表达式,通过这种简单的正则来获取一个不带参数的url
看看前面的urls.py里的列表是怎么定义的
from django.conf.urls import url, urlpatterns = [ path('admin/', admin.site.urls), url('^mainpage/',views.mainpage), url('^publisher/',views.publisher), url('^add_publisher/',views.add_publisher), url('^edit_publisher/',views.edit_publisher), url('^delete_publisher/',views.delete_publisher), url('^add_book/',views.add_book), url('^edit_book/',views.edit_book), url('^test/',views.test) ]
注意下这里的正则表达式,我们只用^符号定义了url的起始字符,有些时候还可以用$符号定义字符串的结尾,区别就是
url('^test/',views.test)
这个可以对以test/开始的url请求进行相应,包括带参数的:就像127.0.0.1:8000/test/?year=1这种的
而限定结尾的只对这种指定的url进行相应,如果是二级的路由也不行:127.0.0.1:8000/tetst1/test2,这种url是不会相应的,但是用上面那个只限制开始的就可以。
一个特殊的正则方法
有的时候我们用省略开头和结尾之间的字符串来实现直接用127.0.0.1:8000来直接显示页面(一般是home页面)
url(r'^$',views.home)
我们前面只创建了一个app,和app/views.py里映射的urls.py是一级路由,如果有这么一种情况,我们创建了多个app,那么我们还可以在各个app路径下创建一个新的urls.py,那么这个urls.py里的映射关系就是一个二级的路由。二级路由在使用的时候需要在一级路由中指定一下,就要用到一个叫include的方法。假设我们创建了两个app,路径大概是这样的(这里只放出来了几个重要的py文件)
|----app01 | |-urls.py | |-__init__.py | |-apps.py | |-views.py | |----app02 |-urls.py |-__init__.py |-apps.py |-views.py
一般情况下这两个app用于实现不同的功能。我们可以在各个app下的urls里指定对应的映射。那么在最外面的urls.py就是一级路由,而各个app里新建的urls.py里的映射就是二级路由,我们在使用二级路由的时候要用include的方法把二级路由的py文件导入一级路由
from app01 import urls as urls_app01 from app02 import urls as urls_app02 urlpatterns = [ url(r'^app01',include(urls_app01)), url(r'^app02',include(urls_app02)) ]
然后我们在app内的views里放好各自的映射效果就行了。注意我这里就是为了便于理解把app名字简单起了个app01和app02,真实项目中要起的名字要跟业务逻辑相符。
我们还可以在定义路由关系的时候传递一个“莫名其妙”的参数,这个参数是以字典的方式进行传递的
url(r'^test/',views.test,{'name':'Jack'})
然后在test这个函数中就可以拿到这个参数
def test(request,name): print(name) return HttpResponse(12345)
这种方法用环境非常少,只作为个了解就可以了。
模板中跳转
有些时候有这样一种用法:两个界面是一家公司的,一个页面主要负责租房,另一个页面主要负责卖房子,在各自的页面上都有对方的“友情链接”,这个效果的实现是比较简单的,最简单暴力的方法就是在模板上直接放一个a标签
<body> <h1>这是卖房子的首页</h1> <div> <p>友情链接</p> <a href="/rentinghouse/home">点击查看租房信息</a> </div> </body> 另一个html文件 <body> <h1>这是租房子的首页</h1> <div> <p>友情链接</p> <a href="/salehose/home">点击查看卖房信息</a> </div> </body>
然后我们在url里只要设置好对应的映射就可以了,
url(r'rentinghouse/',views.renting), url(r'salehouse/',vies.sale)
这样写死url的方法叫硬编码。
但是有个问题,万一我们需要对url进行调整,比方我们要把这个salehouse/改成salebuilding(只是这么个意思啊),那么我们并不知到这个salehouse在哪里是被用过的,这时候就要在最初的时候把他写成或的,给他起一个别名,然后用反向解析的方法来使用。
urlpatterns = [ url(r'^rentinghouse/',views.home,name='rentinghouse') ]
然后我们在模板中可以直接使用这个‘别名’:rentinghouse
<body> <h1>这是卖房的首页</h1> <div> <p>友情链接</p> <a href="{% url 'rentinghouse' %}">点击查看租房信息</a> </div> </body>
在模板中就会用这个{% url 'rentinghouse' %}方法获取到指定的。那么以后不论在后期怎么更改路由里的url,都可以直接获取对应的页面。
视图中跳转
上面是在模板中进行跳转,我们也可以在视图中使用下面的方法来跳转
def test(request): return redirect('/rentinghouse/')
但是这里也是个硬编码,也是把url给写死了,所以也可以用反向解析的方法来操作
from django.urls import reverse def test(request): redirect_url = reverse('rentinghouse') return redirect(redirect_url)
要注意的是一旦上线一般情况url是不会在改变的,这里就是讲一下有这么一个方式可以使用。
反向解析的本质就是给URL匹配模式起一个别名,然后通过别名来获取到具体的URL路径。
我们前面在删除数据库的某个元素的时候用到的url是带参数的,类似这样的
127.0.0.1:8000/deleteBook/?id=2 127.0.0.1:8000、deletePubli/?id=3
我们可以通过正则表达式用一个映射来满足两个url的效果
url('^delete/([a-zA-Z]+)/(\d+)$',views.delete)
我们可以建立一个python文件试一试这个正则表达式的用法
import re r = re.compile(r'^delete/([a-zA-Z]+)/(\d+)/$') ret = r.match('delete/author/10/') for i in ret.groups(): print(i) ##########输出########## [Running] python3 -u "/home/qi/pro_code/test2.py" author 10
在正则表达的时候匹配的对象是一个字符串([a-zA-Z])还有一个数字(\d+),如果匹配成功则(这里调用的是group,返回值是个元组)匹配出来的字符串会被作为位置参数传递给视图里的映射函数。
我们可以用下面的方法来试一下传递的函数是怎么样的
def delete(request,*args,**kwargs): print(args) return HttpResponse(12345)
然后访问一下下面的URL:http://127.0.0.1:8000/delete/publisher/12345/,看看能打印出来什么东西:
('publisher', '12345') [02/Apr/2020 14:49:02] "GET /delete/publisher/12345/ HTTP/1.1" 200 5
明显是一个元组。而我们在用正则表达式进行匹配的时候就定了元组的大小是2,如果我们定下URL的规则,还可以直接用下面的方法来指定好参数的名称
def delete(request,table_name,delete_id): print("table:{},delete_id{}".format(table_name,delete_id))
这样的效果可以直接定义到路由中。