文章目录
django项目在创建时,会自动创建一个名为urls.py
的文件。这个文件的作用是配置django应用程序的路由,其中包含了URL模式到视图函数的映射。
官方文档参考:django URL调度器
1 django的路由调度流程
收到客户端的请求后,django通过如下步骤确定执行哪个视图函数:
- django找到根URL配置文件。
默认是项目目录的urls.py
文件。可以通过settings.py
文件中的ROOT_URLCONF
指定其他配置。 - django加载根URL配置文件,找到其中的
urlpatterns
。
urlpatterns
是django.urls.path()
或django.urls.re_path()
的实例组成的列表。 - 遍历
urlpatterns
中的每个URL模式,当请求的URL匹配到URL模式后停止。 - django调用对应的视图,把请求的
HttpRequest
对象和其中的参数传给视图函数。 - 如果没有找到匹配的URL或在匹配期间出现异常,django会调用错误处理视图。
2 路由配置的语法
2.1 基本语法
from django.urls import path, re_path
urlpatterns = [
# 基本语法
path(pattern, view[, kwargs][, name]),
# 正则匹配
re_path(re_pattern, view[, kwargs][, name]),
]
pattern
匹配请求路径的规则。view
所匹配的路径对应的视图函数。kwargs
字典,用于给关联的视图函数传递关键字参数。name
给url地址起别名,反向解析时用。
2.2 捕获路由中的参数
使用尖括号可以捕获请求URL带的参数,然后传给视图函数处理。
urlpatterns = [
path("test/<info>/", view.test_func),
]
/test/abc/
会匹配上面的路由,dhango调用函数view,test_func(info='abc')
2.3 路径转换器
捕获参数时,可以在尖括号内加上路径转换器,限制url传来的值的类型,并做对应的类型转换。
urlpatterns = [
# '/test/123/'可匹配,调用函数view.test_func(num=123)
path("test/<int:num>/", view.test_func),
]
django支持5种类型的转换器:
str
默认转换格式,匹配除了路径分割符外的非空字符串。int
匹配0和正整数。slug
匹配字母、数字、横线和下划线组成的字符串。uuid
匹配格式化的uuid。path
匹配任意非空字符串,包含路径分割符。
2.4 正则匹配
在路径配置时使用正则匹配需要使用django.urls.re_path()
方法。
正则匹配的格式为(?P<name>pattern)
,其中name是匹配到的参数名,pattern是正则表达式。
正则表达式匹配不会进行类型转换,会把字符串格式的参数直接传给视图函数。
# 正则匹配
re_path("test/\d/", views.re_group),
# 正则匹配,位置传参
re_path("test/([a-z])/", views.re_params),
# 正则匹配,传关键字参数(视图函数的参数顺序可变)
re_path("test/(?P<letter2>[A-Z])(?P<letter1>[A-Z])/", views.re_keyword),
2.5 自定义路径转换器
可以自定义路径转换器,实现更复杂的需求。
路径转换器是一个类,它需要满足三个要求:
- 有
regex
属性,用于匹配; to_python(self, value)
方法,用来类型转换;to_url(self, value)
方法,将python类型转换为字符串,用于URL中。reverse()
函数反向解析时会用到这个方法。
from django.urls import path, register_converter
class MonthHandler:
# 匹配一位或两位的月份
regex = "[0-9]{1, 2}"
def to_python(self, value):
return int(value)
def to_url(self, value):
# 填充到两位
return f"{value:0>2}"
register_converter(MonthHandler, "mm")
urlpatterns = [
path("test/2024/<mm:month>", view.test_func),
]
2.6 传递额外参数给视图函数
urlpatterns = [
path("/test/", view.test_func, {"page": 1}),
]
匹配成功时,django调用view.test_func(page=1)
。
3 路由分发
在urlpatterns
中可以用include
来包含其他的URL配置模块。
urlpatterns = [
path("test/", include("test.urls")),
]
请求的URL为"/test/page/12",匹配到"/test/“时,将”/page/12"转发到test.urls
模块中的urlpatterns
进行匹配。
通常会在各个app里创建各自的URL配置,然后在根路由中包含这些配置。django收到请求时,根据匹配结果把请求转发给app下面的URL配置。
include
也可以用来消除路由配置中的冗余:
# 冗余配置
urlpatterns = [
path("<user_id>/main/", view.user_main),
path("<user_id>/login/", view.user_login),
path("<user_id>/history/", view.user_history),
]
# 用include消除冗余
user_patterns = [
path("main/", view.user_main),
path("login/", view.user_login),
path("history/", view.user_history),
]
urlpatterns = [
# 重复使用的模式仅需要写一次
path("<user_id>/", include(user_patterns)),
]
被包含的URL配置,会受到父配置中捕获到的全部参数。
4 反向解析
实际项目中,常常需要获取网站某个页面的URL,为用户展示网址或导航。这样的需求要求URL可以自动更新。
django的路由配置是可以双向使用的。既可以从用户请求的URL找到正确的视图,并提取参数,也可以提供视图函数的标识以及它需要的参数来得到它关联的URL。
路由配置的语法中的name属性可以为url起别名,根据别名来动态解析url的过程叫反向解析。
执行反向解析的工具有以下三种:
层级 | 使用方式 |
---|---|
模板 | url 标签 |
视图 | reverse() 函数 |
模型 | get_absolute_url() 方法 |
4.1 模板层使用url标签
urlpatterns = [
path("test/", views.test, name="test"),
]
<!-- 模板中使用url标签 -->
<a href="{% url 'test' %}">点击跳转</a>
4.2 视图中使用reverse函数
urlpatterns = [
path("test/", views.test, name="test"),
path("test_reverse/", views.test_reverse),
]
# django_app/views.py
def test_reverse(request):
return HttpResponseRedirect(reverse("test"))
访问"/test_reverse/"会跳转到"test/"对应的页面。
reverse()
的全部参数:
reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
- urlconf,指定当前反向解析使用的urlconf模块。
- args,kwargs,传递给url,填充url中的参数。
- current_app,指定当前视图函数所在的app(避免不同应用间url命名冲突的影响)。
4.3 模型的get_absolute_url方法
模型类可以定义一个get_absolute_url()
方法来告诉django入伙获取访问这个对象的URL。这个方法返回一个字符串,经常使用reverse()
实现。
4.4 URL命名空间
一个django项目可以创建多个app,每个app又有很多路由,这些路由之间容易出现命名冲突。
命名空间可以在不同的应用中出现一样的url名称时,正确地实现反向解析。
使用重复的命名时,反向解析查到的会是
urlpatterns
列表中的最靠后的那个。
命名空间包含两部分:应用命名空间和实例命名空间。
应用命名空间
单个应用的所有实例都是同样的命名空间。即使用app_name
关联应用名字。
# django_app/urls.py
app_name = "app1"
urlpatterns = [
path("test/", views.test_func, name="test"),
]
在视图函数中或模板页面可以通过命名空间:模式
的形式在命名空间中查找对应的模式。
def test(request):
return HttpResponseRedirect(reverse("app1:test"))
实例命名空间
使用namespace
用来标识一个应用的特定实例,主要功能是区分同由一个应用创建的不同实例。
# 项目的总路由 urls.py
urlpatterns = [
path('app1/', include('django_app.urls', namespace='one')),
path('app2/', include('django_app.urls', namespace='two')),
]
在视图中通过request
对象的属性来获取访问的是哪个实例:
def test_reverse(request):
return HttpResponseRedirect(reverse("test", current_app=request.resolver_match.namespace))
以上是django框架的路由的内容整理。