53.Django框架之路由层
Django框架之路由层
【一】URL配置介绍
- URL配置(URLconf)就像Django所支撑网站的目录
- 其本质是URL与要为该URL调用的视图函数之间的映射表
【二】路由匹配
1)路径参数相似
# 路由匹配
path('test', views.test),
path('testadd', views.testadd),
会无法跳转到testadd
- url方法第一个参数是路径参数
- 只要第一个参数能够匹配到内容,就会立刻停止匹配,执行视图函数
2)解决路径参数相似问题
-
在参数尾部加一个 /
# 路由匹配 path('test/', views.test), path('testadd/', views.testadd),
-
在输入 url 的时候会默认加一个 /
- Django内部会帮助我们做一个重定向
- 一次匹配不行
- 那就加一个 / 再尝试一次
- Django内部会帮助我们做一个重定向
3)路由系统自动添加 /
-
在配置文件中,有一个参数可以帮助我们干这件事
APPEND_SLASH = True
【三】分组
- 分组就是将某段正则表达式用()括起来
1)无名分组
- 将括号内正则表达式匹配到的内容当做位置参数传给后面的视图函数
# urls.py
re_path(r"^no_name/(\d+)/",no_name)
# views.py
def no_name(request, pk, *args, **kwargs):
print(pk) # 1
print(args) # ()
print(kwargs)# {}
return HttpResponse("no_name")
2)有名分组
- 有名分组就是将括号内正则表达式匹配到的内容当做关键字参数传给后面的视图函数
# urls.py
re_path(r"^have_name/(?P<id>\d+)/",have_name)
# views.py
def have_name(request, id,*args, **kwargs):
print(id) #('1')
print(args) # ()
print(kwargs) # {'id': '1'}
return HttpResponse("have_name")
3)补充
- Django 2 + 取消了无名分组 只有有名分组
【四】反向解析
0)引入
path('user/admin/login/', login),
-
路径过长时,直接编码费时费力、修改困难、且易出错
-
为了解决此问题,Django提供了一种方法:
- 只需在URL中提供一个name参数,并赋值一个定义好的、直观的字符串,通过这个name参数,可反向解析URL、反向URL匹配、反向URL查询等
path('user/admin/login/',login,name='login')
# 用法格式
{% url 'login'%}
1)本质
- 在路由系统中定义一个路由映射规则
- 给此规则起一个名字
- 可通过名字找到对应的映射规则
# 前端格式
{% url '路由规则名称' %}
# 后端
from django.shortcuts import reverse
def eg(reuest):
reverse('规则名称') #解析指定的路由规则
【五】分组反向解析
1)无名分组反向路由解析
# view.py
def no_name(request, *args, **kwargs):
return HttpResponse("no_name")
# urls.py
re_path(r"^no_name/(\d+)/(\d+)", no_name, name="no_name")
# html(前端反向解析)
<a href="{% url 'no_name' 1 2 %}">no_name</a>
# (后端反向解析)
print(reverse('no_name',args=('1','2')))
2)有名分组反向路由解析
# view.py
def you_name(request, *args, **kwargs):
return HttpResponse("you_name")
# urls.py
re_path(r"^you_name/(?P<year>\d+))/",no_name,name="you_name")
# html(前端反向解析)
<a href="{% url 'you_name' '2' %}">you_name</a>
# (后端反向解析)
print(reverse('you_name", kwargs={"year":1}))
【六】路由分发
1)介绍
- 当一个项目中的URL特别多的时候,总路由urls.py的代码非常冗余而且不好维护,这个时候就可以利用路由分发来减轻总路由的压力
2)路由分发系统
-
每个APP下都要属于自己的路由映射规则文件
-
将所有的规则文件统合到一起,在根据制定的规则进行分发
# 【一】原有的路由规则模式 urlpatterns = [ path('user/login/', login), path('user/register/', register), path('user/logout/', logout), path('shop/buy_good/', buy_good), path('shop/payfor/', payfor), ] # 【二】Django的路由分发系统 user_urlpatterns = [ path('user/login/', login), path('user/register/', register), path('user/logout/', logout), ] shop_urlpatterns = [ path('shop/buy_good/', buy_good), path('shop/payfor/', payfor), ] urlpatterns += user_urlpatterns urlpatterns += shop_urlpatterns # 【三】在每一个app下面新建一个 urls.py # 在总的路由中定义每一个子路由规则 path("user/",include("user.urls")), path("shop/",include("shop.urls")),
3)向视图传递额外的参数
# urls.py
path("buy/<int:year>/", buy, {"good_name": "玩偶"}, name="buy")
# views.py
def buy(request,*args,**kwargs):
print(args)
print(kwargs)
return HttpResponse("buy")
# 访问指定网站后返回数据
# ()
# {'year': 2, 'good_name': '玩偶'}
4)传递额外的参数给include()
# urls.py
path("shop/", include("shop.urls"), {"tag": "shop"})
#访问 buy 的时候
#iclude 分发 带了 {"tag": "shop"}
#buy 自己有一个 {"good_name": "玩偶"}
# {'tag': 'shop', 'year': 2, 'good_name': '玩偶'}
【七】名称空间
1)应用命名空间(app_name )
1.引入
- 在两个APP下面分别定义两个 index 函数 以及 路由映射规则
# app_1
def index(request):
return HttpResponse("app_1下的index")
path('index/', index, name="index"),
# app_2
def index(request):
return HttpResponse("app_2下的index"
path('index/',index,name="index"),
<a href="{% url 'index'%}">app_1的index
<a href="{% url 'index'%}">app_2的index
- 出现问题:谁是最后放的,解析就到谁身上
2.解决
- 给每个app加上指定的名称空间
# app_1\urls.py
app_name = 'app_1'
# 前端
<a href="{% url 'app_1:index'%}">app_1的index
# 后端
print(reverse("app_1:index"))
2)实例命名空间(namespace)
- 总路由进行分发的时候指定 app_name 以及 namespace 名称空间
path("app_1/", include(("app_1.urls", "app_1"),namespace="app_1")),
path("app_2/", include(("app_2.urls", "app_2"),namespace="app_2")),
- 使用方式和上面一致
【八】虚拟环境
1)介绍
- 每创建一个虚拟环境就类似于重新下载了一个纯净的python解释器
- 但是虚拟器不建议下载太多,创建虚拟环境是需要消耗磁盘空间的
2)导出与安装
1.导出项目模板文件
pip freeze > requirements.txt
2.安装项目模板文件
pip install -r requirements.txt
【九】路径转换器
- Django路径转换器 Django2.x 开始出现的
- 在每一个路由中都可能会进行携带参数,解决参数的携带问题于是就有了路径转换器
1)语法
path("路由规则",视图函数名,name="路由解析名")
2)五种转换器
-
str
- 匹配处理 " / " 之外的非空字符串
- 若表达式不含转换器,则默认匹配字符串
-
int
- 匹配0或任何正整数,返回一个int
-
slug
- 匹配任意由 ASCII字母、数字、字符、下划线 组成的段标签
-
uuid
- 匹配一个格式化的UUID,为了防止多个 URL 映射到同一个页面,必须包含破折号并且字符都为小写
-
path
- 匹配非空字段,包括路径分隔符 ' / '
3)自定义转换器
-
创建一个文件(路径不能有中文、空格)
-
在文件中定义方法
class FourDigitYearConverter: # 此属性名为正则表达式(regex),用于匹配四位数的年份字符串 regex = r'[0-9]{4}' def to_python(self, value): """ 将接收到的字符串值解析为Python整数类型表示四位数的年份。 示例:输入 "2024" 会转换为 2024 """ return int(value) def to_url(self, value): """ 根据给定四位数年份(value)将其格式化为URL安全的四位数字形式,例如 "2024" -> "2024". 注意这里的 "匹配的regex是四个数字" 应更改为 "此方法针对四位数的年份字符串" 例如:输入 "2024" 会返回 "2024", 保持四位数且无前导零。 """ return '%04d' % value
-
使用:
-
在视图函数中引入当前自定义转换器
-
将自定义的转换器注册成Django的转换器
- from django.urls import register_converter
-
导入转换器
- from user.path_converters import FourDigitYearConverter
-
注册转换器
- register_converter(自定义转换器规则, '自定义转换器名字')
- parse_self = register_converter(FourDigitYearConverter, 'my_path')
-
在路由中使用转换器
- path("
self_parse/<my_path:param>/", self_parse, name="self_parse
")
- path("
def self_parse(request, param, *args, **kwargs):
print(param, type(param)) # 9999 <class 'int'>
print(args)
print(kwargs)
return redirect(reverse("index_home"))