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)
包含include的路由系统(二级路由)

 我们前面只创建了一个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)

这种方法用环境非常少,只作为个了解就可以了。

命名URL以及URL的反向解析

模板中跳转

有些时候有这样一种用法:两个界面是一家公司的,一个页面主要负责租房,另一个页面主要负责卖房子,在各自的页面上都有对方的“友情链接”,这个效果的实现是比较简单的,最简单暴力的方法就是在模板上直接放一个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))

这样的效果可以直接定义到路由中。

原文地址:https://www.cnblogs.com/yinsedeyinse/p/12556026.html