首页 > 其他分享 >04. 路由控制

04. 路由控制

时间:2023-09-25 18:01:09浏览次数:28  
标签:控制 04 views URL re urls import path 路由

一、简单配置

  URL 配置的本质是 URL 与要为该 URL 调用的视图函数之间的 映射表。通过这种方式告诉 Django,对于客户端发过来的某个 URL 调用哪一段逻辑代码执行。

  用户通过在浏览器中输入 URL 和单击链接来请求网页,因此需要确定项目需要哪些 URL。我们新建一个 Django 项目,并在项目的主文件夹 Django 中的文件 urls.py 中添加要请求的路径:

from django.contrib import admin
from django.urls import path, re_path

from app import views

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    path('admin/', admin.site.urls),

    # 这里URL使用正则表达式,^表示开头匹配,$表示结尾匹配
    re_path(r'^acticles/2003/$', views.special_case_2003),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^acticles/([0-9]{4})/$', views.year_archive),
    re_path(r'^acticles/(\d{4})/(\d{2})/$', views.month_archive),
]

  视图函数接受请求的信息,准备好生成网页所需要的数据,再将这些数据发给浏览器。我们再新建一个应用程序,并在 app 文件夹中的文件 views.py 中添加视图函数:

from django.shortcuts import HttpResponse

# Create your views here.
def special_case_2003(request):
    # HttpResponse 响应对象,将数据返回给浏览器
    return HttpResponse("special_case_2003")

def year_archive(request, year):
    return HttpResponse(f"{year}")

def month_archive(request, year, month):
    return HttpResponse(f"{year}-{month}")

  我们在浏览器中输入 URL http://localhost:8000/acticles/2003/ 访问:

简单配置1

  我们在浏览器中输入 URL http://localhost:8000/acticles/2004/ 访问:

简单配置2

当 URL 与多个请求路径匹配成功时,会匹配上面的那一个请求路径;

若从 URL 中捕获一个值,只需要在它周围放置一对圆括号,分组即可;

二、有名分组

  上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获 URL 中的值并以 位置 参数传递给视图函数。在 Python 正则表达式中,可以使用 命名正则表达式组 的语法(?P<name>pattern)将捕获的值作为 关键字参数 而不是位置参数传递给视图函数。其中,name 是组的名称,pattern 是要匹配的模式。

 修改项目的主文件夹 Django 中的文件 urls.py 中的请求路径:

from django.contrib import admin
from django.urls import path, re_path

from app import views

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    path('admin/', admin.site.urls),

    # 这里URL使用正则表达式,^表示开头匹配,$表示结尾匹配
    re_path(r'^acticles/2003/$', views.special_case_2003),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^acticles/([0-9]{4})/$', views.year_archive),
    re_path(r'^acticles/(?P<y>\d{4})/(?P<m>\d{2})/$', views.month_archive),
]

  修改 app 文件夹中的文件 views.py 中的视图函数:

from django.shortcuts import HttpResponse

# Create your views here.
def special_case_2003(request):
    # HttpResponse 响应对象,将数据返回给浏览器
    return HttpResponse("special_case_2003")

def year_archive(request, year):
    return HttpResponse(f"{year}")

def month_archive(request, m, y):
    return HttpResponse(f"{y}-{m}")

  我们在浏览器中输入 URL http://localhost:8000/acticles/2004/12 访问:

有名分组

三、路由分发

  在实际开发过程中,一个 Django 项目会包含多个应用 ,这时候如果我们只在主路由里进行配置就会显得很乱,所以通常会在每个应用里,创建各自的 urls.py(文件名随意)路由模块,然后从根路由出发,将 应用所属的 URL 请求,全部转发到相应的 urls.py 模块中。而这个从主路由转发到各个应用路由的过程叫做路由的 分发,而它的实现是使用 include() 函数来完成的

  修改项目的主文件夹 Django 中的文件 urls.py 中的请求路径:

from django.contrib import admin
from django.urls import path, re_path, include

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    path('admin/', admin.site.urls),

    # 路由分发
    re_path(r"^app/", include("app.urls"))
]

  在 app 应用中新建一个 urls.py 文件:

from django.urls import re_path

from app import views

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    # 这里URL使用正则表达式,^表示开头匹配,$表示结尾匹配
    re_path(r'^acticles/2003/$', views.special_case_2003),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^acticles/([0-9]{4})/$', views.year_archive),
    re_path(r'^acticles/(?P<y>\d{4})/(?P<m>\d{2})/$', views.month_archive),
]

  我们在浏览器中输入 URL http://localhost:8000/app/acticles/2003/ 访问:

路由分发1

  我们在浏览器中输入 URL http://localhost:8000/app/acticles/2004/ 访问:

路由分发2

如果我们还想向之前一样访问,URL 中没有 app,re_path() 方法的第一个参数可以传入空字符;

四、反向解析

 每个视图函数都有一个和其相对应的路由,但是如果它们之间的匹配关系发生了变化,那么与之对应的访问地址也需要跟着发生改变,这是极其不方便的。因此我们可以用一种动态解析 URL 的方法来避免。我们可以在 path() 中使用 name 关键字参数给对应路由起别名,从而让与之对应的链接或者跳转,会根据这个别名来动态解析 URL,这个动态解析 URL 路径的过程就是 反向解析

   path() 函数接受三个实参。第一个是一个字符串,帮助 Django 正确的 路由(route)请求。收到请求的 URL 后,Django 力图将请求路由给一个 视图,并为此搜索所有的 URL 模式,以找到与当前请求匹配的。如果请求的 URL 与任何既有的 URL 模式都不匹配,Django 将返回一个错误页面。

  path() 的第二个实参指定要调用 views.py 中的哪个函数。

  path() 的第三个实参将为这个 URL 模式起个别名,让我们能在其它项目文件中轻松地引用它。每当需要提供这个主页地链接时,都将使用这个名称,而不编写 URL。

【1】、使用 URL 模板标签实现反向解析

  修改 app 应用中 urls.py 文件:

from django.urls import path

from app import views

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    path(r"login/", views.login, name="login")
]

  修改 app 应用中 views.py 文件:

from django.shortcuts import render, HttpResponse

# Create your views here.
def login(request):

    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        if user == "root" and pwd == "root":
            return HttpResponse("登录成功")
        else:
            return HttpResponse("用户名或者密码错误!")
    else:
        # 浏览器地址栏中直接输入网址回车,是GET请求,返回登录页面
        return render(request, "app/login.html")

  在 template 文件夹下新建一个 app 文件夹,专门用来存放 app 应用中的模板。然后新建一个 login.html 文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="post" action="{% url "login" %}">
        用户名:<input type="text" name="user"><br>
        密 码:<input type="password" name="pwd"><br>
        <input type="submit">
    </form>
</body>
</html>

  这里我们使用了模板标签,模板标签是用花括号和百分号({% %})表示的,实际上是一小段代码,生成要在网页中显示的信息。这里的的模板标签 {% url "login" %} 与 app 中的 urls.py 文件中定义的名称 login 的 URL 模式匹配。

  通过模板标签生成 URL,能很容易的确保链接是最新的:只需要修改 urls.py 中的 URL 模式,Django 就会在网页被请求时自动插入修改后的 URL。

  我们还要把 Django 项目下的 settings.py 文件下的 MIDDLEWARE 列表下的 'django.middleware.csrf.CsrfViewMiddleware' 注释掉,否则点击表单提交的时候,浏览器会返回 Forbidden (403) 页面。

csrf

Forbidden

【2】、使用 reverse() 函数实现反向解析

  修改 app 应用中 urls.py 文件:

from django.urls import re_path

from app import views

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    # 这里URL使用正则表达式,^表示开头匹配,$表示结尾匹配
    re_path(r'^acticles/2003/$', views.special_case_2003, name="special_case_2003"),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^acticles/([0-9]{4})/$', views.year_archive, name="year_archive"),
    re_path(r'^acticles/(?P<y>\d{4})/(?P<m>\d{2})/$', views.month_archive, name="month_archive"),
]

  修改 app 应用中 views.py 文件:

from django.shortcuts import HttpResponse
from django.urls import reverse

# Create your views here.
def special_case_2003(request):
    url = reverse("special_case_2003")
    # HttpResponse 响应对象,将数据返回给浏览器
    return HttpResponse(url)

def year_archive(request, year):
    # 反向解析与具体的视图函数无关
    val = reverse("special_case_2003")
    # 如果反向解析出的内容有正则表达式,则需要替换正则表达式
    url = reverse("year_archive", args=(year,))
    return HttpResponse(f"{url}<br>{val}")

def month_archive(request, m, y):
    val = reverse("special_case_2003")
    res = reverse("year_archive", args=(y,))
    url = reverse("month_archive", args=(y, m))
    return HttpResponse(f"{url}<br>{val}<br>{res}")

反向解析1

反向解析2

五、名称空间

  名称空间(namespace)是标识符的可见范围。一个标识符可在多个名称空间中定义,它在不同名称空间的含义是互不干扰的。这样,在一个新的名称空间中可以定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的标识符的定义在其它名称空间中。

  在命令行中,我们使用如下命令在创建一个应用 app01 和 app02:

python manage.py startapp app01
python manage.py startapp app02

  修改项目的主文件夹 Django 中的文件 urls.py 中的请求路径,添加 app01 和 app02 的路由:

from django.contrib import admin
from django.urls import path, re_path, include

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    path('admin/', admin.site.urls),

    # 路由分发
    re_path(r"^app/", include("app.urls")),
    re_path(r"^app01/", include("app01.urls")),
    re_path(r"^app02/", include("app02.urls")),
]

  由于 name 没有作用域,Django 在反解 URL 时,会在项目全局顺序搜索,当查找第一个 name 指定 URL 时,立即返回。我们在开发项目中,会经常使用 name 属性反解 URL,当不小心在不同的应用的 URL 中定义相同的 name 时,可能会导致 URL 反解错误。

【1】、app01 应用的修改

  app01 应用中新建一个 urls.py 文件:

from django.urls import re_path

from app01 import views

urlpatterns = [
    re_path("index/", views.index, name="index"),
]

  修改 app01 应用中 views.py 文件:

from django.shortcuts import HttpResponse
from django.urls import reverse

# Create your views here.
def index(request):
    # 反向解析
    url = reverse("index")
    return HttpResponse(f"app01 index<br>{url}")

【2】、app02 应用的修改

  app02 应用中新建一个 urls.py 文件:

from django.urls import re_path

from app02 import views

urlpatterns = [
    re_path("index/", views.index, name="index"),
]

  修改 app02 应用中 views.py 文件:

from django.shortcuts import HttpResponse
from django.urls import reverse

# Create your views here.
def index(request):
    url = reverse("index")
    return HttpResponse(f"app02 index<br>{url}")

反向解析混乱1

反向解析混乱2

  我们可以用名称空间解决 URL 解析混乱的问题,在项目的主文件夹 Django 中的文件 urls.py 中的为 app01 和 app02 指定 namespace 参数。

from django.contrib import admin
from django.urls import path, re_path, include

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    path('admin/', admin.site.urls),

    # 路由分发
    re_path(r"^app/", include("app.urls")),
    re_path(r"^app01/", include(("app01.urls", "app01"))),
    re_path(r"^app02/", include(("app02.urls", "app02"))),
]

  修改 app01 应用中 views.py 文件:

from django.shortcuts import HttpResponse
from django.urls import reverse

# Create your views here.
def index(request):
    # 反向解析
    url = reverse("app01:index")
    return HttpResponse(f"app01 index<br>{url}")

  修改 app02 应用中 views.py 文件:

from django.shortcuts import HttpResponse
from django.urls import reverse

# Create your views here.
def index(request):
    url = reverse("app02:index")
    return HttpResponse(f"app02 index<br>{url}")

解决反向解析混乱1

解决反向解析混乱2.png

六、URL转换器

  我们在使用 re_path() 函数捕获的参数都是字符串类型,在视图函数中我们需要用什么类型的数据还需要自己手动转换才行。并且,如果多个路由中都使用相同的正则表达式,一旦规则改变之后,我们还需要手动修改其它使用这些正则表达式的路由。在 Django 2.0 版本中,我们可以通过 path() 解决上述问题。

  修改 app 应用中 urls.py 文件:

from django.urls import re_path, path

from app import views

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    # 这里URL使用正则表达式,^表示开头匹配,$表示结尾匹配
    re_path(r'^acticles/2003/$', views.special_case_2003, name="special_case_2003"),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^acticles/(\d{4})/$', views.year_archive, name="year_archive"),
    # <>表示分组
    path(r'acticles/<int:y>/<int:m>/', views.month_archive, name="month_archive"),
]

  修改 app 应用中 views.py 文件:

from django.shortcuts import HttpResponse
from django.urls import reverse

# Create your views here.
def special_case_2003(request):
    url = reverse("special_case_2003")
    # HttpResponse 响应对象,将数据返回给浏览器
    return HttpResponse(url)

def year_archive(request, year):
    # 如果反向解析出的内容有正则表达式,则需要替换正则表达式
    url = reverse("year_archive", args=(year,))
    print(year)
    print(type(year))
    return HttpResponse(url)

def month_archive(request, m, y):
    url = reverse("month_archive", args=(y, m))
    print(y)
    print(type(y))
    print(m)
    print(type(m))
    return HttpResponse(url)

  path() 方法中使用尖括号(<>)从 URL 中捕获值,捕获值中可以包含一个转换器类型,比如 <int:name> 捕获一个整形变量。若没有转换器,将匹配字符串。

  Django 默认支持以下 5 个转换器:

转换器 含义
str 匹配除了路径分隔符(/)之外的非空字符
int 匹配正整数,包含 0
slug 匹配字母、数字、横杠、下划线组成的字符串
uuid 匹配格式化的 uuid
path 匹配任何非空字符、包含了路径分隔符

? 符号不能作为匹配路径,因为 ? 会作为 GET 请求的路径和参数的分隔符;

  对于一些复杂或者复用的需要,可以定义自己的转换器。转换器是一个类,它的要求有三点:

  1. regex 类属性,字符串类型
  2. to_python(self, value) 方法,value 是由类属性 regex 所匹配的字符串,返回具体的 Python 变量值,以供 Django 传递到对应的视图函数中;
  3. to_url(self, value) 方法,和 to_python() 方法相反,value 是一个具体的 Python 变量值,返回其字符串,通常用于 URL 反向引用。

  在 app 文件夹中新建一个 convert.py 文件,专门用于存放自定义的转换器。

class MonthConvert:
    regex = "\d{2}"

    def to_python(self, value):
        return int(value)

    # 反向解析时使用
    def to_url(self, value):
        return "%02d" % value

  修改 app 应用中 urls.py 文件:

from django.urls import re_path, path, register_converter

from app import views
from app.convert import MonthConvert

# 注册自定义的转换器
register_converter(MonthConvert, "mm")

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    # 这里URL使用正则表达式,^表示开头匹配,$表示结尾匹配
    re_path(r'^acticles/2003/$', views.special_case_2003, name="special_case_2003"),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^acticles/(\d{4})/$', views.year_archive, name="year_archive"),
    # <>表示分组
    path(r'acticles/<int:y>/<mm:m>/', views.month_archive, name="month_archive"),
]

标签:控制,04,views,URL,re,urls,import,path,路由
From: https://www.cnblogs.com/kurome/p/17728492.html

相关文章

  • vue 路由动画
    安装npmi-Sanimate.cssmain.ts引入import'animate.css';routerconstroutes:RouteRecordRaw[]=[{path:'/',alias:['/login'],component:()=>import('@/views/Login.vue'),},{path:&#......
  • 静态路由与BFD联动实现快速检测链路状态使路由表快速收敛
     实现目的:1.默认情况,PC1和PC2之间的通信使用AR1-AR9-AR10-AR2链路通信(主链路),当AR1-AR9-AR10-AR2链路中任何一点的链路断开后,路由会以毫秒级速度切换到AR1-AR3-AR2(备链路),实现网络的连通性。2.当主链路恢复后,路由又切回到主线路。 实验前的配置基础:1.配置PC和路由器端口IP;2......
  • 在idea的控制台使用命令报错XXX无法识别为命令或改变了环境变量后idea环境未同步更新
    报错XXX无法识别为命令是当前环境中不存在XXX配置,当前环境不是说电脑的系统环境,比如使用的idea那当前环境就是idea的配置环境:打开设置(ctrl+alt+s) 在Value中添加XXX对应的路径,记得加分号(;)。 ......
  • vue安装路由
    一、安装命令:npminstallvue-router--save或者cnpminstallvue-router--save二、新建一个router.js router.js大致内容1import{createRouter,createWebHistory}from'vue-router'23constroutes=[4{5path:'/',//主页6......
  • 迅为RK3588核心板在工业机器人控制产品中的应用方案
     迅为RK3588核心板在工业机器人控制产品中可以发挥重要作用,为工业自动化和机器人控制提供高性能的计算和多媒体处理能力。以下是RK3588核心板在工业机器人控制产品中的应用方案:   运动控制:RK3588核心板可以用于控制工业机器人的运动,包括关节控制、轨迹规划和速度控制。......
  • [CF704D] Captain America
    题目描述SteveRogersisfascinatedwithnewvibraniumshieldsS.H.I.E.L.Dgavehim.They'realluncolored.Thereare$n$shieldsintotal,the$i$-thshieldislocatedatpoint$(x_{i},y_{i})$ofthecoordinateplane.It'spossiblethattwo......
  • vue实现大文件切片上传、断点续传、并发数控制等
     一、上传按钮和进度条等<div><h2>上传文件</h2><divref="drag"class="drag"><inputclass="file"type="file"@change="handlerChange"/></div><el-progressstyle="......
  • Spring 04 SpringAOP 切面编程
    Aop:面向切面,在不修改代码的前提下对方法进行增强 pom.xml<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version>......
  • MySQL实战实战系列 04 深入浅出索引(下)
    在上一篇文章中,我和你介绍了InnoDB索引的数据结构模型,今天我们再继续聊聊跟MySQL索引有关的概念。 在开始这篇文章之前,我们先来看一下这个问题: 在下面这个表T中,如果我执行select*fromTwherekbetween3and5,需要执行几次树的搜索操作,会扫描多少行? 下面是这......
  • Ubuntu18.04编译安装Ffmpeg6.0
    本文仅使用Ffmpeg来推RTSP流,其他用途请谨慎参考。1、安装基础库apt-getinstallyasmapt-getinstalllibsdl1.2-devapt-getinstalllibstdl2-devapt-getinstallbuild-essentialaptinstalllibspeex-dev2、安装pkg-configaptintallpkg-config设置环境变量(如果不知......