路由
2023年8月3日大约 5 分钟
路由
在视图完成之后,想要让客户端的请求可以正常匹配到对应的视图函数,就需要给每个视图函数做对应的路由映射。
路由匹配顺序
总分路由
Django的主要路由信息定义在工程同名目录下的urls.py文件中,该文件是Django解析路由的入口。
每个子应用为了保持相对独立,可以在各个子应用中定义属于自己的urls.py来保存该应用的路由。然后用主路由文件包含各应用的子路由数据。
在任何时候,urlpatterns
都可以"include"
其他URLconf
模块。这本质上是一组位于其他url
之下的"roots"
。
每当Django遇到时include()
,它都会截断直到该处匹配的URL的任何部分,并将剩余的字符串发送到包含的URLconf中以进行进一步处理。
djangodemo/urls.py
:项目总路由
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('book.urls')) # 包含图书应用的子路由
]
apps/book/urls.py
: 图书应用的子路由
from django.urls import path
from .views import Index
urlpatterns = [
path('', Index.as_view()),
]
主路由
也可将工程的全部路由信息都定义在主路由文件中,子应用不再设置urls.py。
from django.contrib import admin
from django.urls import path
from book.views import Index
urlpatterns = [
path('admin/', admin.site.urls),
path('', Index.as_view())
]
路由匹配规则
path
path
: 写的非正则路由(route
)两个必须参数:
route
和view
;两个可选参数:kwargs
和name
。即路由和视图是必填参数route
是一个匹配URL的准则(类似正则表达式)。当Django响应一个请求时,它会从urlpatterns的第一项开始,按顺序依次匹配列表中的项,直到找到匹配的项。这些准则不会匹配GET和POST参数或域名。例如,URLconf在处理请求https://www.example.com/myapp/
时,它会尝试匹配myapp/
。处理请求https://www.example.com/myapp/?page=3
时,也只会尝试匹配myapp/
。view
:当 Django 找到了一个匹配的准则,就会调用这个特定的视图函数,并传入一个HttpRequest对象作为第一个参数,被“捕获”的参数以关键字参数的形式传入。kwargs
:任意个关键字参数可以作为一个字典传递给目标视图函数。name
: 为你的URL取名能使你在 Django 的任意地方唯一地引用它,尤其是在模板中。这个有用的特性允许你只改一个文件就能全局地修改某个URL模式
正则捕获到的参数都是字符串,所以如果函数需要用的其他数据类型,可以在函数中直接转换,也可以在路由中直接转换。
转换器(django2.0 以上默认使用的是path转换器)
str
,匹配除了路径分隔符(/
)之外的非空字符串int
,匹配正整数,包含0。slug
,匹配字母、数字以及横杠、下划线组成的字符串。uuid
,匹配格式化的uuid
,如075194d3-6885-417e-a8a8-6c931e272f00
。path
,匹配任何非空字符串,包含了路径分隔符(/
)(不能用问号,因为问号在url地址有特殊含义。)
from django.urls import path
from . import views
urlpatterns = [
path('articles/2003/', views.special_case_2003),
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),
]
/articles/2005/03/ # 将匹配第三条,并调用views.month_archive(request, year=2005, month=3);
/articles/2003/ # 匹配第一条,并调用views.special_case_2003(request);
/articles/2003 # 将一条都匹配不上,因为它最后少了一个斜杠,而列表中的所有模式中都以斜杠结尾;
/articles/2003/03/building-a-django-site/ # 将匹配最后一个,并调用views.article_detail(request, year=2003, month=3, slug="building-a-django-site"
注意:
- 要捕获一段url中的值,需要使用尖括号,而不是之前的圆括号;
- 可以转换捕获到的值为指定类型,比如例子中的
int
。默认情况下,捕获到的结果保存为字符串类型,不包含/
这个特殊字符; - 匹配模式的最开头不需要添加
/
,因为默认情况下,每个url
都带一个最前面的/
。
re_path
如果路径和转换器语法不足以定义URL模式,则也可以使用正则表达式。使用 re_path()
代替path()
。
在Python正则表达式中,已命名正则表达式组的语法为(?P<name>pattern)
,其中name
是组的名称,并且 pattern
是要匹配的某种模式。
示例URLconf,使用正则表达式重写:
from django.urls import path, re_path
from . import views
urlpatterns = [
path('articles/2003/', views.special_case_2003),
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),
]
注意:
- 无论正则表达式进行哪种匹配,每个捕获的参数都将作为字符串发送到视图。
- 当从使用re_path()切换为使用path(), re_path()反之亦然时,特别重要的是要注意视图参数的类型可能会发生变化,因此您可能需要调整视图。
- 当命名的组与未命名的组两种样式混合使用时,任何未命名分组
path('(\d+)/',view)
都会被忽略,只有命名分组path('(?P<year>\d+)/',view)
才会传递到视图函数。 - 未命名分组将正则表达式匹配到的内容当作位置参数,命名分组将正则表达式匹配到的内容当作关键字参数。