python 学习之 django

django请求生命周期流程图

路由匹配

路由

路由简单来说如下:

path('URL路径(网址后缀)',函数名)

一旦有 URL 路径匹配成功,Django 会调用相应的视图函数,并结束整个路由的匹配

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login)
]

路由结尾的斜杠

  • 默认情况下不写斜杠,django会做二次处理

    第一次匹配不上 会让浏览器加斜杠再次请求

  • django配置文件中可以指定是否自动添加斜杠
    APPEND_SLASH = False

URLconf是所有整个Django的入口,一般情况下,一个URL,完整写法如下:

urlpatterns = [
    path(正则表达式, views视图函数,参数,别名),
]

参数说明:

  1. 正则表达式:一个正则表达式字符串
  2. views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
  3. 参数:可选的要传递给视图函数的默认参数(字典形式)
  4. 别名:一个可选的name参数

from django.urls import path

from . import views

urlpatterns = [
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<int:pk>/', views.article_detail),
]
  1. 要捕获一段url中的值,需要使用尖括号,而不是之前的圆括号;
  2. 可以转换捕获到的值为指定类型,比如例子中的<int:name>。默认情况下,捕获到的结果保存为字符串类型,不包含/这个特殊字符;
  3. 规则的前面不需要添加/,因为默认情况下,每个url都带一个最前面的/。比如:articles, 不能写成 /articles。

path转换器

当网址后缀不固定的时候 可以使用转换器来匹配。

Django默认情况下内置下面的路径转换器:

  1. str

    匹配任何非空字符串,但不含/

    若没有专门指定转换器,默认使用这个

  2. int

    匹配0和正整数,返回一个int类型

  3. slug

    可理解为注释、后缀、附属等概念,是url拖在最后的一部分解释性字符。

    该转换器匹配任何ASCII字符以及连接符和下划线,如‘ building-your-1st-django-site ’

  4. uuid

    匹配一个uuid格式的对象。

    为了防止冲突,规定必须使用破折号,所有字母必须小写,如‘075194d3-6885-417e-a8a8-6c931e272f00’

  5. path

    匹配任何非空字符串,重点是可以包含路径分隔符/

    这个转换器可以匹配整个url而不是一段一段的url字符串。

转换器匹配到的内容会当做视图函数的关键字参数传入

转换器有几个叫什么名字,那么视图函数的形参必须对应:

# URL (urls.py)
urlpatterns = [
	path('func/<int:year>/<str:info>/', views.func)
]

# 函数  (views.py)
def func(request,year,info):
  		pass

re_path 正则匹配

如果路径和转换器语法不足以定义URL模式,可以使用正则表达式。这时需要使用re_path()而不是path()。

在Python正则表达式中,命名正则表达式组的语法是 (?P<name>pattern),其中 name 是组的名称,pattern 是需要匹配的规则。

from django.urls import path, re_path
from . import views
urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    #表示articles/2003/这个路径映射views模块的special_case_2003函数
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    #表示匹配4个0-9的任意数字
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
    ]
#注意:上面匹配都加了小括号,这些括号里面的值会当作参数传递到后面的视图函数中

re_path与path()不同的主要在于两点:

  1. year中匹配不到10000等非四位数字,这是正则表达式决定的
  2. 传递给视图的所有参数都是字符串类型。而不像path()方法中可以指定转换成某种类型。

正则匹配之无名分组

无名分组按位置传参,一一对应。

views 中除了 request,其他形参的数量要与 urls 中的分组数量一致。

# urls.py
urlpatterns = [
    re_path("^index/([0-9]{4})/$", views.index),
]

# views.py
def index(request, year):  # 一个形参代表路径中一个分组的内容,按顺序匹配
    pass

正则匹配之有名分组

(?P<组名>正则表达式)

有名分组按关键字传参,与位置顺序无关。

views 中除了 request,其他形参的数量要与 urls 中的分组数量一致, 并且 views 中的形参名称要与 urls 中的组名对应。

# urls.py
urlpatterns = [
    re_path("^index/(?P[0-9]{4})/(?P[0-9]{2})/$", views.index),
]

# views.py
def index(request, year, month):   # 一个形参代表路径中一个分组的内容,按关键字对应匹配
    pass

django版本区别

  • 在django1.11中 只支持正则匹配 并且方法是 url()
  • django2,3,4中,path()、re_path() 等价于 url()

反向解析

在实际的Django项目中,经常需要获取某条URL,为生成的内容配置URL链接。

若页面上提前写死了很多URL,一旦URL发生变化会导致所有页面相关链接失效。

为了解决这个问题,Django提供了一种解决方案,只需在URL中提供一个name参数,并赋值一个你自定义的、好记的、直观的字符串。

通过这个name参数,可以反向解析URL、反向URL匹配、反向URL查询或者简单的URL反查。

在需要解析URL的地方,对于不同层级,Django提供了不同的工具用于URL反查:

  • 在模板语言中:使用url模板标签。(也就是写前端网页时)
  • 在Python代码中:使用reverse()函数。(也就是写视图函数等情况时)
  • 在更高层的与处理Django模型实例相关的代码中:使用get_absolute_url()方法。(也就是在模型model中)

简单来说,利用反向解析,当路由层 url 发生改变,在视图层和模板层动态反向解析出更改后的 url,免去修改的操作。

反向解析一般用在模板中的超链接及视图中的重定向。

普通路径

在 urls.py 中给路由起别名,name="路由别名"

# urls.py 
path("login1/", views.login, name="login")

在 views.py 中,从 django.urls 中引入 reverse,利用 reverse("路由别名") 反向解析:

# views.py 
return redirect(reverse("login"))

在模板 templates 中的 HTML 文件中,利用 {% url "路由别名" %} 反向解析。

<form action="{% url 'login' %}" method="post"> 

正则路径(无名分组)

在 urls.py 中给路由起别名,name="路由别名"

re_path(r"^login/([0-9]{2})/$", views.login, name="login")

在 views.py 中,从 django.urls 中引入 reverse,利用 reverse("路由别名",args=(符合正则匹配的参数,)) 反向解析。

return redirect(reverse("login",args=(10,)))

在模板 templates 中的 HTML 文件中利用 {% url "路由别名" 符合正则匹配的参数 %} 反向解析。

<form action="{% url 'login' 10 %}" method="post">

正则路径(有名分组)

在 urls.py 中给路由起别名,name="路由别名"

re_path(r"^login/(?P<year>[0-9]{4})/$", views.login, name="login")

在 views.py 中,从 django.urls 中引入 reverse,利用 reverse("路由别名",kwargs={"分组名":符合正则匹配的参数}) 反向解析。

return redirect(reverse("login",kwargs={"year":3333}))

在模板 templates 中的 HTML 文件中,利用 {% url "路由别名" 分组名=符合正则匹配的参数 %} 反向解析。

<form action="{% url 'login' year=3333 %}" method="post">

路由分发(urls分层模块化)

通常,我们会在每个app里,各自创建一个urls.py路由模块,然后从根路由出发,将app所属的url请求,全部转发到相应的urls.py模块中。

总路由
	path('app01/', include('app01.urls')),
	path('app02/', include('app02.urls')),
子路由
	path('after/', views.after)  # app01
	path('after/', views.after)  # app02
    
"""
当项目特别大 应用特别多的时候 可以使用路由分发 非常方便!!!
"""

命名空间

命名空间(英语:Namespace)是表示标识符的可见范围。

一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。

一个新的命名空间中可定义任何标识符,它们不会与任何重复的标识符发生冲突,因为重复的定义都处于其它命名空间中。

存在问题:路由别名 name 没有作用域,Django 在反向解析 URL 时,会在项目全局顺序搜索,当查找到第一个路由别名 name 指定 URL 时,立即返回。当在不同的 app 目录下的urls 中定义相同的路由别名 name 时,可能会导致 URL 反向解析错误。

解决:使用命名空间。

普通路径

定义命名空间(include 里面是一个元组)格式如下:

include(("app名称:urls","app名称"))

path("app01/", include(("app01.urls","app01"))) 
path("app02/", include(("app02.urls","app02")))

views中的函数中使用

在 views.py 中使用名称空间,语法格式如下:

reverse("app名称:路由别名")

return redirect(reverse("app01:login")

模板中使用

在 templates 模板的 HTML 文件中使用名称空间,语法格式如下:

{% url "app名称:路由别名" %}

<form action="{% url 'app01:login' %}" method="post">
posted @ 2022-09-01 21:31  梦想有双休  阅读(312)  评论(0)    收藏  举报