【django】3 (django路由) 路由配置和反向解析

发布于:2025-04-03 ⋅ 阅读:(20) ⋅ 点赞:(0)


django项目在创建时,会自动创建一个名为urls.py的文件。这个文件的作用是配置django应用程序的路由,其中包含了URL模式到视图函数的映射。

官方文档参考:django URL调度器


1 django的路由调度流程

收到客户端的请求后,django通过如下步骤确定执行哪个视图函数:

  1. django找到根URL配置文件。
    默认是项目目录的urls.py文件。可以通过settings.py文件中的ROOT_URLCONF指定其他配置。
  2. django加载根URL配置文件,找到其中的urlpatterns
    urlpatternsdjango.urls.path()django.urls.re_path()的实例组成的列表。
  3. 遍历urlpatterns中的每个URL模式,当请求的URL匹配到URL模式后停止。
  4. django调用对应的视图,把请求的HttpRequest对象和其中的参数传给视图函数。
  5. 如果没有找到匹配的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 自定义路径转换器

可以自定义路径转换器,实现更复杂的需求。
路径转换器是一个类,它需要满足三个要求:

  1. regex属性,用于匹配;
  2. to_python(self, value)方法,用来类型转换;
  3. 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框架的路由的内容整理。


网站公告

今日签到

点亮在社区的每一天
去签到