zl程序教程

您现在的位置是:首页 >  后端

当前栏目

[Django] 路由系统

2023-09-11 14:22:54 时间

浏览之前,请先阅读以下文章

1.Django项目创建


URL是Uniform Resource Locator的简写,中文名为统一资源定位符,是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。

互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它

一个URL通常由以下几部分组成:

scheme://host:port/path/?query-string=xxx#anchor

scheme: 代表的是访问的协议,一般为http或者https以及ftp等

host: 存放资源的主机名/域名/ip地址,比如www.baidu.com

port: 端口号,当你访问一个网站的时候,浏览器默认使用80端口

path: 访问资源的路径,例如www.baidu.com/article/12,后面的article/12就是path

query-string: 查询字符串,例如www.baidu.com/s?wd=copy,后面的wd=copy就是查询字符串

anchor: 锚点,前端用来做页面定位的

URL中所有字符都是ASCII字符集,如果出现非ASCII字符,比如中文,浏览器会进行编码再进行传输

URL是Web服务的入口,用户通过浏览器发送过来的任何请求,都要发送到一个指定的URL地址,然后服务器会将响应返回给浏览器。路由就是用来处理URL和函数之间关系的调度器

当一个用户请求Django站点的一个页面时,是路由系统通过对url的路径部分进行匹配,一旦匹配成功就导入并执行对应的视图来返回响应

Django的路由流程如下:

①查找全局urlpatterns变量,即study_django/urls.py文件中定义的urlpatterns变量

②按照先后顺序,对URL逐一匹配urlpatterns列表中的每个元素

③找到第一个匹配时停止查找,根据匹配结果执行对应的处理函数

④如果没有找到匹配或出现异常,Django进行错误处理

提示Tips:项目文件目录下的urls.py文件,在该文件中定义了一个变量urlpatterns,它是一个列表,其中每一个元素都是一个url模式,定义了url和视图函数的对应关系

1.路由模块

在Django中路由模块一般命名为urls.py

每个路由模块中都会包含一个urlpatterns变量,它是一个django.urls.path()或django.urls.re_path()实例的列表

主路由模块

最外层的路由模块,路由解析的入口。通常是项目目录下的urls.py模块

子路由模块

主路由包含的其他路由都是子路由,一般都是各自应用目录下的urls.py模块,需要自己去创建urls.py

2.路由形式

Django可支持以下形式的路由

①精确字符串格式

一个精确URL匹配一个操作函数,适合对静态URL的响应,URL字符串不以' / '开头,但要以' / '结尾,例如

path('admin/', admin.site.urls),

path('articles/', views.article_list), 

path()函数语法格式

path(route, view, kwargs=None, name=None)

参数说明 

route匹配的请求​​​​​​​路径,可理解为一个匹配URL的准则(字符串类型),当Django响应一个请求时,它会从urlpatterns的第一项开始,按顺序依次匹配列表中的项,直到找到匹配的项,然后执行该项映射的视图函数或者include函数分发的下级路由

view: 指的是route匹配成功后​​​​​​​,需要调用视图函数(当Django找到了一个匹配URL的准则,就会调用这个特定的视图函数)     

kwargs: 可以传递额外的参数到对应的视图函数中,其为可选参数(字典类型)

name: 为URL取别名,能使我们在Django的任意地方唯一地引用它,其为可选参数

实例1 
在study_django目录下创建views.py,编写如下代码

from django.http import HttpResponse

def article_list(request):
    return HttpResponse("article_list函数")

 在study_django/urls.py文件中创建路由,代码如下

from django.contrib import admin
from django.urls import path
# 导入自定义的views模块
from . import views 

urlpatterns = [
    path('admin/', admin.site.urls),
    # 新增添加
    path('articles/', views.article_list),
]

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/,结果如下

②路径转换器格式

通常情况下,在匹配URL的同时,通过URL进行参数获取和传递,路径转换器的使用方式非常简单,只需要在捕获符号<>中,按照' <类型:变量名> '语法格式即可

path('articles/<int:year>/', views.year_archive), 

path('articles/<int:year>/<int:month>/', views.month_archive),

path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),

格式转换类型说明
str匹配除路径分隔符( / )外的非空字符,默认转换类型
int匹配0和正整数
slug匹配字母、数字、横杠、下划线组成的字符串,str的子集
uuid匹配格式化的UUID,如075194d3-6885-417e-a8a8-6c931e272f00
path匹配任何非空字符串,包括路径分隔符

实例2 

在study_django目录下创建views.py,编写如下代码

from django.http import HttpResponse

def year_archive(request,year):
    return HttpResponse(f'year_archive函数接受参数year:{year}')

def month_archive(request,year,month):
    return HttpResponse(f'month_archive函数接受参数year:{year},month:{month}')

def article_detail(request,year,month,slug):
    return HttpResponse(f'article_detail函数接受参数year:{year},month:{month},slug:{slug}')

在study_django/urls.py文件中创建路由,代码如下 

from django.contrib import admin
from django.urls import path
# 导入自定义的views模块
from . import views 

urlpatterns = [
    path('admin/', admin.site.urls),
    # 新增添加
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/2023/,结果如下

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/2023/03/,结果如下 

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/2023/03/python/,结果如下

③正则表达式格式

如果路径和转化器语法不能很好地定义URL模式,也可以使用正则表达式

使用正则表达式定义路由时,需要使用re_path()而不是path()

re_path()函数语法格式

re_path(route, view, kwargs=None, name=None)

注意与path()不同的是,route部分包含正则表达式;view、kwargs和name参数与path()相同

在Python正则表达式中,命名正则表达式组的语法格式如下

(?P<name>pattern) 

提示Tips:正则匹配使用的'?P'中字母P需要大写;name是组名,pattern是要匹配的模式 

实例3

在study_django目录下创建views.py,编写如下代码 

from django.http import HttpResponse

def article_list(request):
    return HttpResponse("article_list函数")

def year_archive(request,year):
    return HttpResponse(f'year_archive函数接受参数year:{year}')

def month_archive(request,year,month):
    return HttpResponse(f'month_archive函数接受参数year:{year},month:{month}')

def article_detail(request,year,month,slug):
    return HttpResponse(f'article_detail函数接受参数year:{year},month:{month},slug:{slug}')

在study_django/urls.py文件中创建路由,代码如下 

# 导入path和re_path
from django.urls import path,re_path
# 导入自定义的views模块
from . import views

urlpatterns = [
    path('articles/list/', views.article_list),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
]

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/list/,结果如下

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/2017/,结果如下 

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/2017/08/,结果如下  

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/2017/08/DMU/,结果如下   

3.路由分配(子路由的使用)

在开发过程中,随着项目复杂度增加,定义的路由也会越来越多,如果全部路由都定义在主路由study_django/urls.py文件的urlpatterns变量中,代码会特别凌乱

为此,我们可以将前缀内容相同的路由设置为一组,然后使用include()函数包含分组的路由 

实例4 

主路由模块study_django/urls.py中添加子路由如下

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    # 新增添加
    path('article/', include('article.urls')),  
]

我们将study_django/urls.py文件中包含"article/"前缀的路由作为一组,使用include()函数引入了article.urls模块,所以需要在article目录下创建子路由模块urls.py,编写如下代码

# 导入path
from django.urls import path
# 导入自定义的views模块
from . import views

# 将'index/'和视图views.index进行映射
urlpatterns = [
    path('index/', views.index)
]

打开article/views.py,编写如下代码

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello World, My name is article.")

完成上述操作之后,重新运行服务 

我们就可以在浏览器中通过http://127.0.0.1:8000/article/index/,访问如下结果

提示Tips: path()函数中设置的参数名需要和视图函数中调用的参数名一致!

4.扩展练习案例

练习案例1

涉及知识点:path()中kwargs参数的使用

在study_django目录下创建views.py,编写如下代码

from django.http import HttpResponse

def content(request,**kwargs):
    print(kwargs) # {'author': 'Andy', 'age': 18}
    print(kwargs.get("author")) # Andy
    author = kwargs.get("author")
    age = kwargs.get("age")
    return HttpResponse("{}是本文作者,年龄是{}".format(author, age))

 在study_django/urls.py文件中创建路由,代码如下

# 导入path
from django.urls import path
# 导入自定义的views模块
from . import views

urlpatterns = [
    # 传递一个Python字典作为额外的参数给对应的视图函数
    path('articles/',views.content,{"author":"Andy","age":18}),
]

启动服务,在浏览器中输入网址http://127.0.0.1:8000/articles/,结果如下

练习案例2

涉及知识点:path()中name参数的使用

在项目目录study_django/urls.py文件中创建路由,代码如下

# include用来分配的
from django.urls import path,include

# 主路由:只用来分配
urlpatterns = [
    path('article/', include("article.urls")),
]

在article目录下创建子路由模块urls.py,编写如下代码 

from django.urls import path
from . import views

# 子路由
urlpatterns = [
    path("test01/",views.test),
    # 这里就对此条path使用了参数name!
    path("content/",views.content,{"author":"Andy","age":18},name = "fox"),
]

打开article/views.py,编写如下代码

# redirect是重定向,reverse是将url的name解析成url的函数
from django.shortcuts import redirect,reverse
from django.http import HttpResponse
import time

# article应用下面的视图函数
def content(request,**kwargs):
    author = kwargs.get("author")
    age = kwargs.get("age")
    return HttpResponse("{}是本文作者,年龄是{}".format(author,age))

#登录页
def test(request):
    print("登录成功")
    time.sleep(3)
    # 下面两者作用一模一样
    # return redirect("/article/content")    # 跳转到唱歌页面
    return redirect(reverse("fox"))     # reverse可以将当前这个fox解析为它所对应的url地址,即/article/content

启动服务,在浏览器中输入网址http://127.0.0.1:8000/article/test01/, 等待3秒后会跳转到http://127.0.0.1:8000/article/content/,显示Andy是本文作者,年龄是18

上述解决了无论url的地址如何改变,只要它的name属性不变,这些关于它的重定向都可以正常执行