第2章——Django的路由
2.1 认识路由
URL是网站Web服务的入口。用户在浏览器中输入URL发出请求之后,后端的Django应用会在路由系统中根据URL查找并运行对应的视图函数,然后返回信息到浏览器中。Django的路由系统也被称为URL conf,这反映了URL和视图函数的映射关系:遇到某个URL就执行对应的视图函数。
当我们创建一个Django项目的时候,在项目目录下面会生成一个urls.py文件。在该文件中定义了Django项目的主要路由信息。该文件也是整个项目路由解析的入口。除此之外,在新建的应用中也可以使用独立的路由配置文件urls.py。但应用中的urls.py需要手动创建。这里我们接着前面的项目进行练习。
前面文章回顾: 第1章- Django入门简介
2.1.1 路由系统的基本配置
在项目的urls.py中,有一个名称为“urlpatterns”的列表,其中存放着项目中的URL路由规则,以下代码作为一个例子:
from django.contrib import admin
from django.urls import path,include
from app import views
urlpatterns = [
path('index/',views.index), # 访问路由,制定视图函数
path('index/',views.index,name='index'), # 第二种写法
# 上述写法二选其一,推荐第二种
path('admin/',admin.site.urls), # admin模块下的路由配置
]
在上面的代码中,默认导入了admin模块和path()方法,并在urlpatterns列表中指向admin后台管理系统的URL管理规则(这是一条默认的路由规则)。该urlpatterns列表中定义的路由为整个项目的根路由。
一个path()函数对应一条路由规则。当用户请求"index/"这个URL的时候,通过配置项找到app应用下面view.py中对应的视图函数index()执行并返回结果。
path()函数的语法格式如下:
path(路由,视图函数,别名)
2.1.2 [实战]用“路由包含”简化项目的复杂度
随着业务模块越来越多,路由规则也会越来越复杂。可以用“路由包含”来简化项目的复杂度:为每一个应用创建一个urls.py文件,把相关的路由配置都放在每个应用的urls.py文件中。这样,当用户发起请求时,会从根路由开始寻找每个应用的路由信息,生成一个完整的路由列表。当Django从当前请求中获取路由地址后,会先在这个路由列表中进行匹配,然后执行路由信息所关联的视图函数,从而完成整个请求过程。
1.路由配置规则
在项目的urls文件中,urlpatterns列表会从上到下进行匹配。
- 如果匹配成功,则调用path()函数中的第2个参数所指定的视图函数,且不会再往下继续匹配。
- 如果匹配不成功,则返回404错误。
- 如果在应用中定义了子路由,则在根路由中使用include(‘应用名.urls’)来加载子路由。如果URL的第1部分被匹配,则其余部分会在子路由进行匹配。
- 路由信息一般以“/”结尾。
2.实战
路由包含的写法是Django必学的一个技能点,接下来对项目中的应用的路由进行管理。我们之前只创建了一个应用:app。这里我们再创建两个应用,以此来更好的理解路由包含的使用方法。
创建应用:
$ python manage.py startapp app1
$ python manage.py startapp app2
这里可以看到应用app1和app2被创建。
- (1) 这里我们在“myshop/urls.py”添加如下代码。其中,include()函数的参数为应用的URL配置文件:
urlpatterns = [
#path('index/',views.index), # 访问路由,制定视图函数
path('index/',views.index,name='index'), # 第二种写法
path('',include('app1.urls')),
path('',include('app2.urls')),
path('admin/',admin.site.urls), # admin模块下的路由配置
]
- (2) 新建应用路由文件“app1/urls.py”,“app2/urls.py”,在其中添加如下代码:
from django.urls import path
from app2 import views # 这里记得调用对应的app
urlpatterns = [
path('app1/index/',views.index), # 在app2中写:'app2/index'
]
- (3) 分别在"app1/views.py"和"app2/views.py"增加视图函数index(),代码如下所示:
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse("这里是app1中的index方法。") # 同理,app2修改一下名称即可
- (4) 运行结果如下所示:
当访问"http://127.0.0.1:8000/app1/index/“,结果如下:
当访问"http://127.0.0.1:8000/app2/index/”,结果如下:
同样的,我们在控制台也是可以看到请求路由的信息:
2.1.3 解析路由参数
在浏览新闻网站的某个新闻详情网页的时候,URL地址一般为“show/1/”,“show/2/”这样的格式,我们不可能为所有的新闻详情页面都预先配置好路由规则,所以需要引入URL参数进行动态的配置。
1.编写带URL参数的路由
这里通过一个例子来学习带URL参数的路由。
- (1)这里我们编写app1和app2下面的urls.py的代码,增加配置路由:
urlpatterns = [
path('app1/show/<int:id>/',views.show), # app2中同理
]
- (2)分别编写app1和app2中的views.py,增加视图函数show()
def show(request,id):
return HttpResponse("app1中的show方法,参数为id,值为"+str(id))
- (3)这里访问一下对应的路由:
2.介绍URL参数
在路由规则:"path(‘app1/show/<int.id>/’,views.show)"中,<>中的内容被称为URL参数。其余法格式如下:
<参数数据类型:参数名称>
举例:
<uuid:id>
<str:name>
URL参数有4种数据类型:
参数数据类型 | 说明 |
---|---|
str | 任意非空字符,不包含"/",默认类型 |
int | 匹配0和正整数 |
slug | 匹配任何ASCII字符、连接符和下划线 |
uuid | 匹配一个uuid格式的字符串,该对象必须包含“-”,所有字母必须小写 |
3.URL参数解析的实例
这里通过实例演示URL参数解析。
- (1)打开应用路由文件"app1/urls.py",添加如下路由规则:
urlpatterns = [
path('app1/article/<uuid:id>/',views.show_uuid,name='show_uuid'),
path('app1/article/<slug:q>/',views.show_slug,name='show_slug'),
]
- (2) 打开"app1/views.py",增加视图函数show_uuid(),如以下代码:
def show(request,id):
return HttpResponse("app1中的show方法,参数为id,值为"+str(id))
def show_uuid(request,id):
return HttpResponse("app1中的show_uuid方法,参数为id,值为"+str(id))
def show_slug(request,q):
return HttpResponse("app1中的show_slug方法吗,参数为q,值为"+str(q))
- (3) 这里访问一下上面新增加的两条路由规则:
(1)http://127.0.0.1:8000/app1/article/4b301c53-5fe6-4f71-9d23-a8935e80f641/
(2)http://127.0.0.1:8000/app1/article/shirong123/
- (4) 补充说明:当我们测试uuid参数的时候,随机输入的uuid会被识别为slug参数,这是因为在这里uuid参数格式做了要求,具体如下:
UUID识别码格式:
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
这里为了测试方便我们可以用python自带的uuid库来完成uuid的随机生成:
macbook@shirongediannao ~ % python3
Python 3.9.13 (main, May 24 2022, 21:28:44)
[Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import uuid
>>> uuid.uuid4()
UUID('a4631fc6-32c4-4d96-8c01-79d0e85ae864')
>>>
2.1.4 [实战]用re_path()方法正则匹配复杂路由
re_path()方法和path()方法作用一样。在re_path()方法中编写URL时可以使用正则表达式,所以在这里我们用它。
- 1.路由中的正则表达式
路由中的正则表达式的语法格式如下:
(?P<name>pattern)
其中,name是匹配的字符串名称,pattern是要匹配的模式。常见的正则表达式如下:
正则表达式 | 说明 |
---|---|
. | 匹配任意单个字符 |
\d | 匹配任意一个数字 |
\w | 匹配字母,数字,下划线 |
* | 匹配0个或者多个字符(如"\d*"代表0个或者多个数字) |
[a-z] | 匹配a~z中任意一个小写字符 |
{1,5} | 匹配1~5个字符 |
- 2.实例
这里通过一个实例来演示路由中的正则表达式:
(1)修改app1中的urls.py,在其中添加如下代码:
from django.urls import path,re_path # 这里需要补上re_path,否则会报错缺少依赖
from app1 import views
urlpatterns = [
path('app1/article/<uuid:id>/',views.show_uuid,name='show_uuid'),
path('app1/article/<slug:q>/',views.show_slug,name='show_slug'),
re_path(r'^app1/list/(?P<year>\d{4})/',views.article_list),
re_path(r'^app1/page/(?P<page>\d+)&key=(?P<key>\w+)',views.article_page,name="article_page"),
]
(2)解析代码
app1/list/(?P<year>\d{4})/
解释:接收以“app1/list/”开头、后面跟4位整数的路由。
app1/page/(?P<page>\d+)&key=(?P<key>\w+)
解释:接收以“app1/page/”开头、后面跟任意整数,且第2个参数可以是字母、数字和下划线的路由。
(3)编辑app1中的views.py代码,增加视图函数article_list()和article_page():
def article_list(request,year):
return HttpResponse("app1中的article_list方法,参数为year,指定4位,值为"+str(year))
def article_page(request,page,key):
return HttpResponse("app1中的article_page方法,参数为page,任意数字,值为"+str(page)+" 参数key,字母数字下划线,值为"+key)
(4)根据上述编写的路由规则访问这两个路由
http://127.0.0.1:8000/app1/list/2023/
http://127.0.0.1:8000/app1/page/10&key=shi_rong
2.1.5 反向解析路由
在Django的路由配置中,可以给一个路由配置项目名,然后在视图函数或模板的HTML文件中进行调用。
- 1.介绍
先了解以下的路由配置:
path('app1/url_reverse/',views.url_reverse,name='app1/url_reverse'),
说明如下:
(1)在name后可以跟任意字符串。为了避免冲突,建议使用的规则名为:“应用名_配置项目名称”
(2)name相当如配置项的别名。有了这个别名就可以在视图函数或者模板的HTML文件中调用它
根据name得到的路由配置项中的URL地址,被称为“反向解析路由”。这样的好处是:只要name不变,URL地址可以任意改变。
- 2.实例
这里通过一个实例来学习反向解析路由
(1)打开app1中的urls.py,增加一段反向解析路由,如以下代码所示:
path('app1/url_reverse',views.url_reverse,name='app1_url_reverse'),
(2)打开app1中的views.py,增加视图函数url_reverse(),如以下代码所示:
# 在最上面导入reverse
...
from django.urls import reverse
...
def url_reverse(request):
# 使用reverse()方法反向解析
print("在views()函数中使用reverse()方法解析的结果:"+reverse("app1_url_reverse![请添加图片描述](https://img-blog.csdnimg.cn/912ff80874c447229244946d91947b87.png)
"))
return render(request,"1/url_reverse.html")
(3)在template中新建文件url_reverse.html:
<div>
在HTML中使用url标签进行反向解析
<br>
{% url 'app1_url_reverse' %}
<div>
(4)运行后访问路由:http://127.0.0.1:8000/app1/url_reverse/
这里我们可以发现在HTML代码中调用的是:app1_url_reverse,然而最后调用的是:url_reverse,也就是说在urls.py中只要增加反向解析的路由,就可以实现该功能。