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视图函数,参数,别名),
]
参数说明:
- 正则表达式:一个正则表达式字符串
- views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 参数:可选的要传递给视图函数的默认参数(字典形式)
- 别名:一个可选的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),
]
- 要捕获一段url中的值,需要使用尖括号,而不是之前的圆括号;
- 可以转换捕获到的值为指定类型,比如例子中的
<int:name>。默认情况下,捕获到的结果保存为字符串类型,不包含/这个特殊字符;- 规则的前面不需要添加
/,因为默认情况下,每个url都带一个最前面的/。比如:articles, 不能写成 /articles。
path转换器
当网址后缀不固定的时候 可以使用转换器来匹配。
Django默认情况下内置下面的路径转换器:
-
str
匹配任何非空字符串,但不含
/若没有专门指定转换器,默认使用这个
-
int
匹配0和正整数,返回一个int类型
-
slug
可理解为注释、后缀、附属等概念,是url拖在最后的一部分解释性字符。
该转换器匹配任何ASCII字符以及连接符和下划线,如‘ building-your-1st-django-site ’
-
uuid
匹配一个uuid格式的对象。
为了防止冲突,规定必须使用破折号,所有字母必须小写,如‘075194d3-6885-417e-a8a8-6c931e272f00’
-
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()不同的主要在于两点:
- year中匹配不到10000等非四位数字,这是正则表达式决定的
- 传递给视图的所有参数都是字符串类型。而不像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">

浙公网安备 33010602011771号