二、django中的路由系统

news2024/11/27 4:38:50

django中的路由系统

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

django如何处理请求

  1. 当一个请求来到时,django首先到项目中查找根URLconf模块,在其中查找路由匹配规则。
  2. 根URLconf模块,就是项目文件目录下的urls.py文件。在这个文件中定义了一个变量urlpatterns。它是一个列表,其中每一个元素都是一个url模式,定义了url和视图函数的对应关系。
  3. django按顺序运行每个url模式,并在与请求的url匹配的第一个模式停止。
  4. 一旦去中一个url模式匹配,django将导入并调用该视图。
  5. 如果没有匹配的模式,或者在此过程中任何时候引发异常,django调用错误处理视图。

路由模块

在django中路由模块一般命名为url.py

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

根路由模块

最外层的路由模块,路由解析的入口。

django通过设置ROOT_URLCONF来确定主路由模块,通常是项目目录下的urls.py模块。

子路由

主路由包含的其他路由都是子路由。

一般都是各自应用目录下的urls.py模块。

path()

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

  • path函数返回一个对象,表示一个路由规则

  • route:一个字符串,表示url规则

  • view: 一个视图
  • kwargs:一个字典,需要传入的额外参数
  • name:url的命名

案例:

上一节,我们在crm应用中定义了如下路由:

path('index/', views.index)

'index/'和视图views.index进行映射。

include()

  • include(module, namespace=None)

  • 将一个子路由导入到一个URLconf模块中

  • module: URLconf模块(或模块名称)

案例:

上一节,我们在根路由中,通过include包含了crm子路由:

path('crm/', include('crm.urls'))

crm/和子路由crm.urls进行映射。

URLconf在什么上查找

请求的url会被看做是一个普通的Python字符串,URLconf在其上查找并匹配。

进行匹配时不包含GETPOST请求方式的参数以及域名。

例如,https://www.example.com/myapp/ 请求中,URLconf 将查找 myapp/

在 https://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找 myapp/ 。

URLconf不检查使用哪种请求方法。

换句话说,所有请求方法,对同一个URL无论是POST请求GET请求等等,都将路由到相同的视图函数。

案例:

所以在浏览器中访问地址http://127.0.0.1/crm/index/时,URLconf将查找crm/index/

第一步在跟路由中进行匹配,可以匹配到:

path('crm/', include('crm.urls'))

第二步当遇到include()时,它会将匹配到该点的URL部分crm/切掉,并将剩余字符串index/发送到包含的crm.urls模块中进一步匹配

第三/indexcrm.urls路由中可以匹配到:

path('index/', views.index)

没有下一步匹配,直接执行对应的视图函数views.index

注意,这个过程会递归的进行,中间遇到任何一条匹配的路由就会返回。

  

 

在URL中捕获参数

django允许在url中捕获值,若要从URL中捕获值,请使用尖括号。

尖括号定义变量名,捕获的值传递给视图函数相同名称的参数。格式如下:

'<参数名>'

案例:

写一个学生详情接口,通过crm/students/n/返回id为n的学生的信息。

视图代码:

# crm/views.py
def detail(request, pk):
    return HttpResponse('学生id为{}的详情'.format(pk))        # 模拟返回对应学生的详情

路由代码:

# crm
urlpatterns = [
    ...
    path('students/<pk>/', views.detail)
]

现在,在浏览器中访问:http://127.0.0.1:8000/crm/students/2/会返回页面:

注意看路由部分的<pk>,这里的pk对应视图函数的pk形参。django会自动匹配url中这部分的字符串2然后传递给detail函数的pk形参。

路径转换器

上面的案例有个漏洞,如果我们在浏览器中输入http://127.0.0.1:8000/crm/students/aaa/,我们发现它依然可以访问。

在实际开发中,这显然不对,id不可能是个字符串。当然可以在view中进行类型转换,但是不够通用。django中设计了路径转换器,能够在路由匹配时,自动进行转换。

以下路径转换器在默认情况下是可用的:

  • str: 匹配除了路径分隔符/之外的任何非空字符串。如果表达式中不包含转换器,默认为字符串转换器。

  • int: 匹配0或任何整数。返回一个整数类型

  • slug: 匹配任何由ASCII字符或数字组成的slug字符串,加上连字符和下划线。
  • uuid: 匹配格式化的UUID。为了防止多个url映射到同一个页面,必须包含破折号并且必须是小写字母。例如:075194d3-6885-417e-a8a8-6c931e272f00
  • path: 匹配任何非空字符串,包括路径分隔符/。这允许匹配完整的URL路径,而不是像str那样仅匹配url路径部分。

路径转换器的使用方式非常简单,只需要在捕获符号<>中,以以下语法即可:

'<转换器:参数名>'

我们可以将上面的案例修改为:

path('students/<int:pk>/', views.detail)

然后,我们再次访问`http://127.0.0.1:8000/crm/students/aaa/,结果是404。

当然,我们也可以捕获多个值,看如下案例:

视图代码:

# crm/views.py
def student_list(request, year, month):
    return HttpResponse('{}年{}月创建的学生列表'.format(year, month))

路由代码:

# crm/urls.py
urlpatterns = [
    ...
    path('students/<int:year>-<int:month>/', views.student_list),
    path('students/<int:year>/<int:month>/', views.student_list)
]

那么通过urlhttp://127.0.0.1:8000/crm/students/2022/01http://127.0.0.1:8000/crm/students/2022-01/会得到相同的结果。

但是如果访问http://127.0.0.1:8000/crm/students/9527-100/也会得到结果:

这显然又是bug。

路径转换器只能进行简单的类型转换和匹配,还需要更强大的匹配功能,需要用到re_path()函数。

re_path()

  • re_path(route,view, kwargs=None,name=None)函数返回一个对象,表示一条路由规则。
  • route: 一个字符串,表示一个url规则
  • view:一个视图
  • kwargs: 一个字典,需要传入的额外参数
  • name: url命名

path()不同的是,route部分包含正则表达式。

当进行匹配时,从正则表达式中捕获的组会被传递到视图中。

如果组是命名的,则作为命名参数,否则作为位置参数。值以字符串的形式专递,不进行任何类型转换。

命名正则表达式分组的语法是:(?P<name>pattern),其中name是组的名称,pattern是要匹配的某个模式。

下面是前面例子中的路由,使用正则表达式重写:

re_path(r'^students/(?P<year>\d{4})-(?P<month>[1-9]|1[0-2])/$', views.student_list),
re_path(r'^students/(?P<year>\d{4})/(?P<month>[1-9]|1[0-2])/$', views.student_list)

这样写和之前的路由匹配一致,只是:

  • 匹配的url会受到限制,例如:100月将不再匹配,因为月份整数被限制为1-12。
  • 捕获的每个参数都以字符串的形式发送到视图。
  • 当从使用path()切换到re_path()或相反时,特别重要的是注意视图参数的类型会发生变化,因此可能需要调整视图。

使用没有命名分组的正则表达式

除了命名组语法,例如(?P<year>\d{4}),还可以使用较短的未命名组,例如(\d{4})。这种写法并不特别推荐,因为它更容易在匹配的预期含义和视图参数之间意外的一如错误。

注意在实际使用中建议只使用一种,要么命名,要么不命名,因为当两种方式混合使用时,会忽略未命名的组,只将命名的组传递给视图函数。

url命名

path(), re_path()还有一个参数,那就是name,这个参数可以给我们的url命一个名。

那它有什么作用呢?

在实际开发中,经常需要获取最终形式的url,比如嵌入的页面链接和服务端导航(重定向)。

我们来模拟一个登录过程,创建一个登录的函数视图如下:

# crm/views.py
from django.shortcuts import redirect
...


def login(request):
    return redirect('/crm/index/')

配置好url

# crm/urls.py
path('login/', views.login)

当我们访问/crm/login/时会发现页面被重定向到了/crm/index/,但是这里有一个问题:重定向这里的url是硬编码的,万一将来我们要修改这个url(这个几率很大),那么我们需要在代码中修改所有硬编码的url部分。这显然不利于维护。所以,强烈建议不要硬编码URL(这是一个费力,不能扩展,容易出错的注意)。

django提供一个django.shortcuts.reverse()函数,它接受一个url的命名,能反向解析出url的绝对路径。

给crm应用的每条路由都添加一个name。

urlpatterns = [
    path('index/', views.index, name='index'),
    path('students/<int:pk>/', views.detail, name='student_detail'),
    path('students/<int:year>/<int:month>/', views.student_list, name='student_list'),
    path('login/', views.login, name='login')
]

然后修改登录视图如下:

from django.shortcuts import reverse
def login(request):
    url = reverse('index')
    return redirect(url)

这样不管怎么修改url,reverse都可以动态的解析出url。

当有url参数时,可以通过args,kwargs进行传递,例如:

reverse('student_list', kwargs={'year': 2021, 'month': 12})
# 或
reverse('student_list', args=(2021,12))
# 都可以解析出 /crm/students/2021/12/

注意:在reverseargs,kwargs两个参数不能同时使用。

app_name

将url命名为indexlogin非常常见,一个项目中,不同的app给url相同的命名,那怎么区分不同应用相同名称的url呢?

非常简单,在应用下的urls.py文件中定义一个app_name变量,给它赋值为引用的名称,例如在crm/urls.py中定义app_name变量如下:

# crm/urls.py
...
app_name = 'crm'            # 一般和引用同名
...

定义app_name之后,再解析url时,需同时传入app_name,格式如下:

'app_name:url_name'

那么要解析index的url的代码如下:

reverse('crm:index')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167014.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringSecurityOauth2架构Demo笔记

总体分为SpringSecurityOauth2授权码模式演示和密码模式演示 一直下一步,依赖手动导入,SpringBoot版本改成2.2.5.RELEASE,JDK版本1.8 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xml…

Open3D 点云投影至指定球面(Python版本)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 假设球体的相关参数:中心为 C ( x c , y c , z c ) C(x_c,y_c,z_c)

【数据结构和算法】栈—模拟实现Stack和栈相关算法题

文章目录栈的定义Stack模拟实现相关算法题1.栈的压入弹出序列2.逆波兰表达式(后缀表达式)⭐1.什么是逆波兰表达式?如何转换成逆波兰表达式逆波兰表达式如何计算3.有效的括号总结栈的定义 栈作为一种数据结构&#xff0c;是一种只能在一端进行插入和删除操作的特殊线性表。它按…

华为MPLS跨域C2方案实验配置

MPLS隧道——跨域解决方案C1、C2讲解_静下心来敲木鱼的博客-CSDN博客_route-policy rr permit node 10 if-match mpls-labelhttps://blog.csdn.net/m0_49864110/article/details/127634890?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId…

深度学习——长短期记忆网络LSTM(笔记)

长短期记忆网络LSTM&#xff1a; ①隐变量模型存在长期信息保存和短期输入缺失问题&#xff0c;解决方法是LSTM ②发明于90年代 ③使用效果和GRU差别不大&#xff0c;但是实现起来复杂 1.长短期记忆网络 ①忘记门Ft&#xff1a;将值朝0减少 ②输入门It&#xff1a;是否忽…

最容易理解的并查集详解

并查集 并查集&#xff0c;在一些有N个元素的集合应用问题中&#xff0c;我们通常是在开始时让每个元素构成一个单元素的集合&#xff0c;然后按一定顺序将属于同一组的元素所在的集合合并&#xff0c;其间要查找一个元素在哪个集合中。 比如下面这幅图&#xff0c;总共有 10 …

MySQL之存储过程

MySQL存储过程1、基本介绍1.1、介绍存储过程&#xff1a;1.2、特点1.3、基本语法1.3.1、delimiter1.3.1、创建存储过程1.3.2、调用存储过程1.3.3、查看存储过程1.3.4、删除存储过程2、变量2.1、系统变量2.1.1、查询(会话、全局、模糊、精确)2.1.2、设置系统变量2.2、用户定义变…

IB学生必须具备的三大特质

以往的专栏亦提及过&#xff0c;修读IB课程要面对几大挑战。而要应对这些挑战&#xff0c;IB学生须具备以下三大条件&#xff1a; 时间管理能力 IBDP 首先&#xff0c;要对时间分配掌握得很好。两年的IB预科课程非常紧凑&#xff0c;不但每科都有其内部评核&#xff08;Interna…

VMware17虚拟机安装Ubuntu最新版本(Ubuntu22.04LTS)详细步骤

目录 一、概述 二、下载Ubuntu 22.04.1 LTS 三、在VMware虚拟机下安装Ubuntu22.04 四、配置网络 一、概述 Ubuntu是基于Linux内核开发的&#xff0c;免费下载&#xff0c;使用和分享的开源系统。如果需要在Linux下开发程序&#xff0c;这是一个很好的选择。本文介绍了Ubuntu最…

【问题解决】Tomcat启动服务时提示Filter初始化或销毁出现java.lang.AbstractMethodError错误

问题背景 最近在开发项目接口&#xff0c;基于SpringBoot 2.6.8&#xff0c;最终部署到外置Tomcat 8.5.85 下&#xff0c;开发过程中写了一个CookieFilter&#xff0c;实现javax.servlet.Filter接口&#xff0c;代码编译期正常。部署到外置Tomcat 8.5.85 下&#xff0c;在控制…

【Java寒假打卡】Java基础-类加载器

【Java寒假打卡】Java基础-类加载器概述类加载时机类加载的过程-加载类加载的过程-链接类加载的过程-初始化类加载器的分类类加载器-双亲委派模型类加载器-常用方法概述 负责将字节码文件加载到内存中 类加载时机 创建类的实例对象调用类的类方法访问类或者接口的类变量&am…

SymPy符号运算库与latex数学公式

SymPy符号运算库与latex数学公式sympylatexsympy SymPy是一个用于以符号运算为主的符号数学的Python库。它的目标是成为一个全功能的计算机代数系统(CAS)&#xff0c;同时保持代码尽可能的简单&#xff0c;以便易于理解和易于扩展。SymPy完全是用Python编写的。 官网地址:http…

【linux kernel】Linux设备驱动模型 | bus

文章目录一、导读二、与总线相关的数据结构&#xff08;2-1&#xff09;struct bus_type&#xff08;2-2&#xff09;struct subsys_private三、总线的初始化四、总线的操作接口&#xff08;4-1&#xff09;总线的注册&#xff08;4-2&#xff09;总线的注销&#xff08;4-3&am…

Linux的基本使用在Linux上部署程序

linux概述 Linux严格意义来说只是一个"操作系统内核"&#xff0c;一个完整的操作系统 操作系统内核 配套的应用程序 由于 Linux 是一个完全开源免费的内核&#xff0c;因此有些公司/开源组织又基于 Linux 内核&#xff0c;提供了不同的配套程序&#xff0c;这就构…

GAN“家族”又添新成员——EditGAN,不但能自己修图,还修得比你我都好

导语&#xff1a;从风格迁移到特征解耦、语言概念解耦&#xff0c;研究人员正通过数学和语言逐步改善GAN的功能。作者 | 莓酊编辑 | 青暮首先想让大家猜一猜&#xff0c;这四张图中你觉得哪张是P过的&#xff1f;小编先留个悬念不公布答案&#xff0c;请继续往下看。生成对抗网…

【蓝桥杯】历届真题 时间显示(省赛)Java

【问题描述】 小蓝要和朋友合作开发一个时间显示的网站。在服务器上&#xff0c;朋友已经获取了当前的时间&#xff0c;用一个整数表示&#xff0c;值为从1970年1月1日O0:00:00到当前时刻经过的毫秒数。 现在&#xff0c;小蓝要在客户端显示出这个时间。小蓝不用显示出年月日&a…

Allegro如何灌铜操作指导

Allegro如何灌铜操作指导 在做PCB设计平面层的铜皮时候,会需要用到灌铜的操作,如下图 灌铜可以让铜皮自动沿着Antietch画指定网络的铜皮 具体操作如下 点击Add Line命令选择Anti Etch的层面,比如Anti Etch画在L2层,线宽设置为40mil

TCP通信的三次握手和四次挥手详解

TCP通信的三次握手和四次挥手详解 计算机网络参考模型: 应用层:例如Modbus、Http、FTP 传输层:TCP、UDP 网络层:IP 数据链路层:MAC 物理层:RS485、RS232、以太网 TCP的包头: TCP包头为至少20字节 TCP包头解释  源端口号、目的端口号,用于建立连接时,确认源端口(本机…

2.Spring 等框架简单入门了解

1.Spring 1.什么是spring? 一个轻量级Java开发框架,目的是为了解决企业级应用开发 的业务逻辑层和其他各层的耦合问题. 两个核心特性&#xff0c;也就是依赖注入(dependency injection&#xff0c;DI)和面向切面编程(aspect- oriented programming&#xff0c;AOP) 2.IOC(控制…

一文带你秒懂十大排序

目录 一、排序的概述 二、插入排序 1、直接插入排序 2、希尔排序 二、选择排序 1、直接选择排序 2、堆排序 三、交换排序 1、冒泡排序 2、快速排序 四、归并排序 五、计数排序 六、基数排序 七、桶排序 八、排序总结 一、排序的概述 排序就是将一组…