django项目在创建时,会自动创建一个名为urls.py
的文件。这个文件的作用是配置django应用程序的路由,其中包含了URL模式到视图函数的映射。
官方文档参考:django URL调度器
收到客户端的请求后,django通过如下步骤确定执行哪个视图函数:
urls.py
文件。可以通过settings.py
文件中的ROOT_URLCONF
指定其他配置。urlpatterns
。urlpatterns
是django.urls.path()
或django.urls.re_path()
的实例组成的列表。urlpatterns
中的每个URL模式,当请求的URL匹配到URL模式后停止。HttpRequest
对象和其中的参数传给视图函数。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地址起别名,反向解析时用。使用尖括号可以捕获请求URL带的参数,然后传给视图函数处理。
urlpatterns = [
path("test//" , view.test_func),
]
/test/abc/
会匹配上面的路由,dhango调用函数view,test_func(info='abc')
捕获参数时,可以在尖括号内加上路径转换器,限制url传来的值的类型,并做对应的类型转换。
urlpatterns = [
# '/test/123/'可匹配,调用函数view.test_func(num=123)
path("test//" , view.test_func),
]
django支持5种类型的转换器:
str
默认转换格式,匹配除了路径分割符外的非空字符串。int
匹配0和正整数。slug
匹配字母、数字、横线和下划线组成的字符串。uuid
匹配格式化的uuid。path
匹配任意非空字符串,包含路径分割符。在路径配置时使用正则匹配需要使用django.urls.re_path()
方法。
正则匹配的格式为(?P
,其中name是匹配到的参数名,pattern是正则表达式。
正则表达式匹配不会进行类型转换,会把字符串格式的参数直接传给视图函数。
# 正则匹配
re_path("test/\d/", views.re_group),
# 正则匹配,位置传参
re_path("test/([a-z])/", views.re_params),
# 正则匹配,传关键字参数(视图函数的参数顺序可变)
re_path("test/(?P[A-Z])(?P[A-Z])/" , views.re_keyword),
可以自定义路径转换器,实现更复杂的需求。
路径转换器是一个类,它需要满足三个要求:
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/" , view.test_func),
]
urlpatterns = [
path("/test/", view.test_func, {"page": 1}),
]
匹配成功时,django调用view.test_func(page=1)
。
在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("/main/" , view.user_main),
path("/login/" , view.user_login),
path("/history/" , view.user_history),
]
# 用include消除冗余
user_patterns = [
path("main/", view.user_main),
path("login/", view.user_login),
path("history/", view.user_history),
]
urlpatterns = [
# 重复使用的模式仅需要写一次
path("/" , include(user_patterns)),
]
被包含的URL配置,会受到父配置中捕获到的全部参数。
实际项目中,常常需要获取网站某个页面的URL,为用户展示网址或导航。这样的需求要求URL可以自动更新。
django的路由配置是可以双向使用的。既可以从用户请求的URL找到正确的视图,并提取参数,也可以提供视图函数的标识以及它需要的参数来得到它关联的URL。
路由配置的语法中的name属性可以为url起别名,根据别名来动态解析url的过程叫反向解析。
执行反向解析的工具有以下三种:
层级 | 使用方式 |
---|---|
模板 | url 标签 |
视图 | reverse() 函数 |
模型 | get_absolute_url() 方法 |
urlpatterns = [
path("test/", views.test, name="test"),
]
<a href="{% url 'test' %}">点击跳转a>
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)
模型类可以定义一个get_absolute_url()
方法来告诉django入伙获取访问这个对象的URL。这个方法返回一个字符串,经常使用reverse()
实现。
一个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框架的路由的内容整理。