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

04. 路由

时间:2023-11-16 19:55:24浏览次数:34  
标签: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'^articles/2003/$', views.special_case_2003),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^articles/([0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(\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/articles/2003/ 访问:

简单配置1

  我们在浏览器中输入 URL http://localhost:8000/articles/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'^articles/2003/$', views.special_case_2003),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^articles/([0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?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/articles/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'^articles/2003/$', views.special_case_2003),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^articles/([0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<y>\d{4})/(?P<m>\d{2})/$', views.month_archive),
]

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

路由分发1

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

路由分发2

  我们还可以将路由手动划分,把 url 的公共部分提取出来,修改 app 应用的 urls.py 文件,内容如下:

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    # 这里URL使用正则表达式,^表示开头匹配,$表示结尾匹配
    re_path(r'^articles/', ([
        re_path(r'^2003/$', views.special_case_2003),
        re_path(r'^([0-9]{4})/$', views.year_archive),
        re_path(r'^(?P<y>\d{4})/(?P<m>\d{2})/$', views.month_archive),
    ], None, None)),
]

如果我们还想向之前一样访问,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】、使用 reverse() 函数实现反向解析

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

from django.urls import re_path

from app import views

urlpatterns = [
    # 路由配置:路径 ---> 视图函数
    # 这里URL使用正则表达式,^表示开头匹配,$表示结尾匹配
    re_path(r'^articles/2003/$', views.special_case_2003, name="special_case_2003"),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^articles/([0-9]{4})/$', views.year_archive, name="year_archive"),
    re_path(r'^articles/(?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", kwargs={"m":m, "y":y})
    return HttpResponse(f"{url}<br>{val}<br>{res}")

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

reverse反向解析1

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

reverse反向解析2

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

reverse反向解析3

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

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

from django.urls import path

from app import views

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

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

from django.shortcuts import HttpResponse, render


# Create your views here.
def articles(request):
    # render 根据视图提供的数据渲染响应
    return render(request, "app/articles.html")

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", kwargs={"m":m, "y":y})
    return HttpResponse(f"{url}<br>{val}<br>{res}")

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="{% url 'special_case_2003' %}">special_case_2003</a><br>
    <a href="{% url 'year_archive' '2004' %}">special_case_2004</a><br>
    <a href="{% url 'month_archive' y='2004' m='12' %}">special_case_2004_12</a><br>
</body>
</html>

  我们在浏览器地址栏中输入 http://localhost:8000/app/articles/ 访问页面。

URL标签反向解析

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

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

五、名称空间

  名称空间(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}")

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

反向解析混乱1

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

反向解析混乱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}")

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

解决反向解析混乱1

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

解决反向解析混乱2.png

  我们也可以通过 namespace 参数指定名称空间,如果设置 namespace 还需要设置 app_name,否则会报如下错误。

django.core.exceptions.ImproperlyConfigured: 
Specifying a namespace in include() without providing an app_name is not supported. 
Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.

  修改 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"^app01/", include("app01.urls", namespace="app01")),
]

  修改 app01 应用下的 urls.py 文件。

from django.urls import re_path

from app01 import views

app_name = "app01"

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

六、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'^articles/2003/$', views.special_case_2003, name="special_case_2003"),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^articles/(\d{4})/$', views.year_archive, name="year_archive"),
    # <>表示分组
    path(articles/<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'^articles/2003/$', views.special_case_2003, name="special_case_2003"),
    # ()表示分组,分组的内容也会发送给视图函数作为形参
    re_path(r'^articles/(\d{4})/$', views.year_archive, name="year_archive"),
    # <>表示分组
    path(articles/<int:y>/<mm:m>/', views.month_archive, name="month_archive"),
]

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

相关文章

  • Ubuntu 22.04 LTS 安装最新稳定版本nginx、mysql5.7和php7.2
    Ubuntu22.04LTS安装最新稳定版本nginx、mysql5.7和php7.2全部apt-get安装,就是快,迅速。前提是需要在有网络环境的情况下哈!!操作系统版本:Ubuntu22.04LTS一、安装最新稳定版本的nginxapt-getupdate#查看默认安装的nginx版本(默认为1.18。有点老,我们安装最新稳定版本)apt......
  • 504 与413错误处理
    报504错误,我们可以从ngxin上找找看是否是nginx访问超时导致的错误。proxy_connect_timeout1000;proxy_send_timeout1000;proxy_read_timeout1000;send_timeout1000;如果还是不行,那么很可能是fastcgi请求超时导致了程序访问超时fastcgi_connect_timeout1000......
  • 职场小白必备知识点-RIP&OSPF​路由协议
    路由简介作为网络工程师,你需要为某园区规划网络,预计有路由器若干,网络拓扑如下:规划网络之前,我们先来了解一下路由的相关知识。什么是路由所谓的路由,通俗来说就是路由器后台里,一张由目的地址、子网掩码、下一跳构成的表;它的作用是告知路由器需要如何处理收到的数据包;比如,路由器收到......
  • vue2 前后端分离的项目,用宝塔部署,出现域名访问根目录能访问,加任何网址就404
    https://admin.xxx.com/ 访问正常https://admin.xxx.com/index  访问404location/{root/home/ruoyi/projects/ruoyi-ui;try_files$uri$uri//index.html;indexindex.htmlindex.htm;} nginx加上上面这段......
  • 【操作系统MIT 6.1810(2022版)笔记】Lab实验:环境搭建——以Ubuntu20.04为例
    感觉环境搭建没有别人说的那么难。我是双系统用户(Win+Ubuntu20.04),所以直接在Ubuntu上搭建了。听别人说不要用Ubuntu18.04搭建,不知道为什么参考链接:官网环境搭建教程环境搭建打开终端,输入以下命令并回车运行sudoapt-getinstallgitbuild-essentialgdb-multiarchqemu-s......
  • az-204 practice-003
    Question2of50YoumanageanAzureAPIManagementinstance.YouneedtolimitthemaximumnumberofAPIcallsallowedfromasinglesourceforaspecifictimeinterval.Whatshouldyouconfigure?PolicyThisitemteststhecandidate’sknowledgeofpo......
  • Flask之登录认证装饰器、配置文件、路由系统、CBV
    登录认证装饰器fromflaskimportFlask,request,render_template,redirect,session,jsonify,url_forapp=Flask(__name__)#如果要用session,必须加这一句app.secret_key='asdfasdfasdf-lqz-justin'USERS={1:{'name':'李清照','age......
  • SP12304
    题目传送门简述题目:题目要求找出满足条件\(σ(i)=n\)的最小整数\(i\),其中\(σ(i)\)表示\(i\)的所有正因子的和。解题思路:首先定义一个函数\(Suum(i)\),用于计算\(i\)的所有正因子的和。在函数内部,使用一个循环遍历\(i\)的所有可能因子。对于每一个因子\(i\),如......
  • ASP.Net MVC使用特性路由
    ASP.NETMVC中使用特性路由需要在默认路由前调用routes.MapMvcAttributeRoutes();需要注意Action上使用特性路由时需要注意不能以/开头不能写成/Controller/Action如果使用了routes.MapMvcAttributeRoutes();出现不能调用控制器“xx”上的操作方法“xx”,因为该方法是一种泛......
  • day04 进制和编码
    day04进制和编码课程目标:讲解计算机中一些必备的常识知识,让学员了解一些常见名词背后的含义(重在理解)。课程概要:python代码的运行方式进制计算机中的单位编码1.Python代码运行方式脚本式python3~/PycharmProjects/day03/6.作业题讲解.py交互式python32.进......