Django - 初探路由

路由定义规则

准备工作:新建项目MyDjango,新建App index,在项目的index 文件夹里新添加一个空白内容的.py 文件,命名为urls.py。项目结构如下图:

在App(index 文件夹)里添加urls.py 是将所有属于App 的路由都写入该文件中,这样更容易管理和区分每个App的路由地址,而MyDjango 文件夹的urls.py 是将每个App的 urls.py 统一管理。其工作原理如下:

(1) 运行MyDjango 项目时,Django 从 MyDjango 文件夹的urls.py 找到各个App所定义的路由信息,生成完整的路由列表
(2) 当用户在浏览器上访问某个路由地址时,Django 就会收到该用户的请求信息
(3) Django 从当前请求信息获取路由地址,并在路由列表里匹配相应的路由信息,再执行路由信息所指向的视图函数(或视图类) ,从而完成整个请求响应过程。

MyDjango 文件夹得urls.py 代码如下:

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

urlpatterns = [
    # 指向内置Admin后台系统的路由文件 setes.py
    path('admin/', admin.site.urls),
    #  指向index  的路由文件 urls.py
    path('', include('index.urls')),
]

以上定义了两条路由信息,分别是Admin 站点管理 和 首页地址(index)。其中,Admin站点管理在创建项目时自动生成,一般情况下无须修改;首页地址是指index文件夹得urls.py

  • path('admin/', admin.site.urls): 设定Admin得路由信息。'admin/' 代表 127.0.0.1/8001/admin得路由地址,admin.site.urls 指向内置Admin功能所自定义的路由信息
    venv/Lib/site-packages/django/contrib/admin/sites.py
  • path('', include('index.urls')): 路由地址为"",即127.0.0.1:8001 ,通常是网站得首页。路由函数include 是将该路由信息分发给 index得urls.py处理

由于首页地址分发给index 的urls.py 处理,因此下一步需要对index 的urls.py 编写路由规则:

#index\urls.py
from django.urls import path
from index import views

urlpatterns = [
    path('', views.index)
]

路由信息 path('', views.index),的views.index 是指视图函数index处理网站首页的用户请求和响应过程。

#index\views.py
from django.shortcuts import render

def index(request):
    print('this is  a tets')
    return render(request, 'index.html')

index函数必须设置一个参数,参数名不固定,通常以request 进行命名,代表当前用户的请求对象。

请求结果:

从上述列子看到,当启动MyDjango时,Django 会从配置文件setting.py 读取属性ROOT_URLCONF 的值,默认值为MyDjango.urls,代表MyDjango 文件夹的urls.py文件,然后根据ROOT_URLCONF的值来生成整个项目的路由列表。

路由文件urls.py 的路由定义规则是相对固定的,路由列表由urlpatterns 表示,每个列表元素代表一条路由。路由是由Django 的path函数定义的,该函数的第一个参数是路由地址,第二个参数是路由所对应的处理函数(视图函数或视图类),这两个参数是路由定义的必选参数。

路由变量的设置

在日常开发中,有时一个路由可以代表多个不同的页面,如编写带有日期的路由。Django 在定义路由时,可以对路由设置变量,使路由具有多样性。

路由变量类型有字符类型、整型、slug、和uuid,最常用的类型是整型和字符类型

  • 字符类型: 匹配任何非空字符串,但不含斜杠。如果没有指定类型,就默认使用该类型
  • 整型: 匹配0和正整数
  • slgu:可以理解为注释、后缀或附属等概念。常作为路由的解释性字符。可匹配任何ASCCI 字符以及连接符和下划线。能使路由更加清晰易懂。比如网页标题是"13 岁的孩子",其路由地址可以设置为:'13-sui-de-hai-zi'。
  • uuid:匹配一个uuid格式的对象。为了防止冲突,规定必须使用'-' 并且所有字母必须小写。例如:075194d3-6885-417e-a8-a8-6c931e272d00。

根据上述类型变量,在 index 文件夹的urls.py 里新定义路由,代码如下:

from django.urls import path
from index import views

urlpatterns = [
    path('<year>/<int:month>/<slug:day>', views.myvariable)
]

在路由中,使用变量符号'<>' 可以为路由设置变量。在括号里面以冒号划分为两部分,冒号前面代表的是数据类型,冒号后面代表的是变量名,变量名可以自行命名,如果没有设置,默认就是字符类型。上述代码设置了3个变变量:

  • : 数据格式为字符,与<str: year> 的含义一样
  • <int: month>:变量为名month,数据格式为整型
  • <slug: day> :变量名为day,数据格式为slug

视图函数处理请求:

# index\views.py
def myvariable(request, year, month, day):
    return HttpResponse(f'{year} / {month} / {day}')

用连接访问:http://localhost:8001/2024/05/02

如果浏览器输入的路由地址与变量类型不相符,Django 就会提示Page not found:

路由设置的变量要和视图函数的参数保持一一对应。如果数量对不上,那么程序会抛出参数不相符的报错信息:

除了在路由变量地址设置变量外,Django 还支持在路由地址外设置变量(路由的可选变量)。我们在index 的urls.py 和 views.py 中分别新增路由和视图函数,如下:

# index\urls.py
from django.urls import path
from index import views

urlpatterns = [
    path('<year>/<int:month>/<slug:day>', views.myvariable),
    path('', views.index, {'msg': '2024/05/02'}),
]

# index\views.py
def index(request,msg):
    return HttpResponse(f'这是路由地址之外的变量:{msg}')

以上函数可以看出,路由函数path 的第三个参数是 {'msg': '2024/05/02'},该参数的设置规则如下:

  • 只能以字段的形式表示
  • 设置的参数只能在视图函数中获取和使用
  • 字典的一个键值对代表一个参数,参数值
  • 参数值没有数据格式限制,可以为某个实例对象,字符串和列表(元组)等。

正则表达式的路由定义

为了进一步规范日期格式,可以使用正则表达式限制路由地址变量的取值范围。代码如下:

#index\urls.py
from django.urls import path,re_path
from index import views

urlpatterns = [
    re_path('(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2}).html', views.mydata)
]

路由的正则表达式是由路由函数re_path 定义的,正则表达式是以小括号为单位的,每个小括号前后可以使用斜杠或者字符将其分割与结束。 在小括号内部,可分为3部分,以(?P[0-9]{4}) 为例。

  • ?P 是固定格式,字母P 必须大写。
  • 为变量名
  • [0-9]{4} 是正则表达式的匹配模式,代表变量的长度为4,只允许取0~9值

视图函数:

# index\views.py
def mydata(request,year, month,day):
    return HttpResponse(f'{year} / {month} / {day}')

路由地址末端设置了".html",这是一种伪静态URL技术,可以将网址设置为静态网址,用于SEO 搜索引擎的爬取。

命名空间与路由命名

网站规模越大,其网页的数量就会越多,如果网站的网址过多,在管理或者维护上就会存在一定的难度。 Django 为了更好地管理和使用路由,可以为每条路由设置命名空间或路由命名

命名空间

在MyDango 项目里新建应用user,并且在user 文件夹里创建urls.py,然在在配置文件settting.py 的INSTALLED_APP 中添加应用user,使得Django 在运行的时候能够识别到项目应用user,

在MyDango 文件夹的urls.py 重新定义路由信息,分别指向index\urls.py 和 user\urls.py:

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

urlpatterns = [
    # 指向内置Admin后台系统的路由文件 setes.py
    path('admin/', admin.site.urls),
    #  指向index  的路由文件 urls.py
    path('', include(('index.urls', 'index'), namespace='index')),
    #  指向user 文件夹下的 urls.py
    path('user/', include(('user.urls', 'user'), namespace='user')),
]

路由函数include 设有参数arg 和 namespace,参数arg 指向项目应用App 的urls.py 文件,其数据格式以元组或字符串表示,可选参数namespac额 是路由的命名空间。

若要对路由设置参数namespace,则参数arg 必须以元组格式表示,并且元组的长度必须为2。元组的元素说明如下:

  • 第一个元素为项目应用的urls.py 文件。
  • 第二个元素可以自行命名,但不能为空。一般情况下是以项目应用的名称进行命名。

Django 的命名空间 可以为我们快速定位某个项目应用的urls.py,再结合路由命名name 就能快速地从项目应用的urls.py 找到某条路由的具体信息,这样就能有效管理整个项目的路由列表。

路由的使用方式

路由为网站开发定义了具体的网址,不仅如此,它还能被其他功能模块使用,比如视图、模板、模型、Admin 后台 或表单等

在模板中使用路由

# MyDjango\urls.py 配置:
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('index.urls')) # 未使用命名空间
]

# index\urls.py 配置:
urlpatterns = [
    path('<year>/<int:month>/<slug:day>', views.mydate, name='mydate'),  # 路由命名
    path('', views.index),
]

# index\views.py 配置:
def index(request):
    return render(request, 'index.html')

def mydate(request, year, month, day):
    return HttpResponse(f'{year} / {month} / {day}')

模板配置:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <span>Hello World!!!</span>
    <br>
    <a href="{% url 'mydate' '2024' '05' '02'%}">查看日期</a>
</body>
</html>

验证:

模板使用了Django 内置的模板语法 ur 来生成路由地址,模板语法 url 里设置有4个不同的参数,其说明如下:

  • mydate: 代表命名为 mydate 的路由,即index的urls.py 设有字符类型、整型和slug的路由。
  • 2019 :代表路由地址变量year
  • 01:代表路由地址变量 month
  • 10: 代表路由地址变量day

模板语法 url 的参数设置与路由定义是相互关联的,具体说明如下:

  • 若路由地址存在变量,则模板语法url需要设置相应的参数值,参数值之间使用空格隔开
  • 若路由地址不存在变量,则模板语法url 只需要设置路由命名name 即可
  • 若路由地址的变量与模板语法url 的参数数量不同,则在浏览器访问网页的时候会提示NoReverseMathc at 的错误信息

上述例子中,MyDjango\urls.py 在使用函数include 定义路由时并没有设置命名空间。若同时设置了命名空间namespace 和 name,则在模板里使用路由的方式有所变化。

正确使用方式为:

<a href="{% url 'index:mydate' '2024' '05' '02'%}">查看日期</a>

反向解析reverse 和 resolve

Django 的反向解析主要是由函数 reverse 和 resolve 实现:函数reverse 是通过路由命名或可调用视图对象来生成路由地址的;函数resolve 是通过路由地址来获取路由对象信息的。

案例配置信息:

# MyDjango\urls.py:

urlpatterns = [
    # 指向内置Admin后台系统的路由文件 setes.py
    path('admin/', admin.site.urls),
    #  指向index  的路由文件 urls.py
    path('', include(('index.urls', 'index'), namespace='index')),
]
# index\urls.py:

urlpatterns = [
    path('<year>/<int:month>/<slug:day>', views.mydate, name='mydate'),
    path('', views.index),
]

视图中代码如下:

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

def index(request):
    kwargs = {'year': 2024, 'month': 2, 'day': 10}
    args = ['2024', '12', '12']
    # 使用reverse 生成路由地址
    print(reverse('index:mydate', args=args))
    print(reverse('index:mydate', kwargs=kwargs))
    return HttpResponse(reverse('index:mydate', args=args))


def mydate(request, year, month, day):
    args = ['2024', '05', '02']
    result = resolve(reverse('index:mydate', args=args))

    print('kwargs: ', result.kwargs)
    print('url_name: ', result.url_name)
    print('namespace: ', result.namespace)
    print('view_name: ', result.view_name)
    print('app_name: ', result.app_name)
    return HttpResponse(f'{year}/{month}/{day}')

函数index 主要使用反向解析函数reverse 函数来生成路由mydate 的路由地址。函数参数下:

def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):

设有不选参数viewname,其他参数是可选参数,说明如下:

  • viewname:代表路由或可调用视图对象,一般情况下以路由命名name 来生成路由地址的
  • urlconf:设置反向解析的URLconf 模块。默认请况下,使用配置文件setting.py 的ROOT_URLCONF 属性。
  • args:以列表方式传递路由地址变量,列表元素顺序和数量应该与路由地址变量的顺序和数量一致
  • kwargs: 以字典的方式传递路由地址变量,字典的键必须对应路由地址变量名,字典的键值对数量与变量的数量一致
  • current_app: 提示当前正在执行的视图所在的项目应用,主要起到提示作用

在浏览器访问:locahost:8001,当前请求将有视图函数index 处理,reverse 来获取路由名为 mydate 的路由地址并显示在网页上:

控制台输出:

在浏览器访问:localhost:8001/2024/05/02 ,控制台输出:

kwargs:  {'year': '2024', 'month': 5, 'day': '02'}
url_name:  mydate
namespace:  index
view_name:  index:mydate
app_name:  index

路由重定向

Django 的网页重定向有两种方式,第一种方式是理由重定向,第二种方式是自定义视图的重定向。两种重定向方式各有优点,前者是使用Django 内置的视图类 RedirectView 实现的,默认支持HTTP 的GET请求,后者是在自定义视图的响应状态设置重定向,能够让开发者实现多方面的开发需求。

案例:

# index\urls.py
from django.urls import path
from index import views
from django.views.generic import RedirectView
urlpatterns = [
    path('<year>/<int:month>/<slug:day>', views.mydate, name='mydate'),
    path('', views.index),
    path('turnTo', RedirectView.as_view(url='/'), name='turnTo')
]

#index\views.py
from django.shortcuts import HttpResponse, reverse, redirect
from django.urls import resolve

def index(request):
    args = ['2024', '05', '03']
    return redirect(reverse('index:mydate', args=args))


def mydate(request, year, month, day):
    return HttpResponse(f'this is mydate function,param {year}/{month}/{day}')

浏览器上输入:http://localhost:8001/turnTo,发现该网址首先通过视图类RedirectView 重定向到首页,然后再视图函数index 里使用重构定向函数redicet()跳转到路由名为 mydate 的路由地址

posted @ 2024-05-02 10:03  chuangzhou  阅读(55)  评论(0编辑  收藏  举报