二、Django路由Router
在实际开发过程中,一个Django 项目会包含很多的 app ,这时候如果我们只在主路由里进行配置就会显得杂乱无章,所以通常会在每个 app 里,创建各自的urls.py路由模块
,然后从根路由出发,将 app 所属的 url 请求,全部转发到相应的 urls.py 模块中。而这个从主路由转发到各个应用路由的过程叫做路由的分发
re_path正则路由的写法
# re_path正则写法 ()表示正则分组为一个参数 (?P<参数名>regex)
re_path(r'^user_view_ab/(?P<a>\d+)/(?P<b>\d+)/$', user_view_ab, name="user_view_ab")
这样就是匹配user_view_ab/1/2
等数字参数
路由匹配
# 使用url给视图函数传参数
path('index/', index)
path('detail/<int:id>/', detail)# 给url取别名,那么在使用此url的地方(例如页面模板反向解析)可以使用别名。比如:
path('index/',index,name='index')
path('detail/<int:id>/', detail, name='detail')根据路由的name属性,获取路由url
reverse('index') => 路由'index/'
反向解析
Django路由反向解析
是一个非常重要的功能,它可以让我们在代码中使用路由别名替代URL路径,在修改URL时避免代码中的硬编码依赖,同时也可以提高可读性和可维护性。
# 在视图函数中,反向解析url:
from django.shortcuts import render,redirect,reverse
def buy(request):return redirect(reverse('index'))return redirect(reverse('detail',args=[2]))return redirect(reverse('detail',kwargs={"id":2}))#在templates中,使用别名:{% url 'detail' stu.id %}# 使用命名空间:
# 指定命令空间后,使用反向解析时需要加上命名空间,比如:
# 1.在视图函数中:return redirect(reverse('App:index'))
# 2.在templates中:{% url 'App:index'%}
页面之间相互跳转(通过html)
- 在根目录下的
urls.py
添加如下代码
from django.contrib import admin
from django.urls import include, path
from App.views import *
urlpatterns = [# 使用子路由: path("user/", include("App.urls")),# 使用子路由: 使用命名空间path("user/", include(("App.urls","App"), namespace="App")),path('admin/', admin.site.urls),
]
- App/urls.py子路由文件
from tkinter.font import names
from django.urls import path
from App.views import *
urlpatterns = [# 首页path('index/', index, name='index'),# 用户列表path('user_list/', user_list, name='user_list'),
]
- 定义
视图函数
和user_list.html
文件
# 用户列表
def user_list(request):return render(request, 'user_list.html')
- 在想要添加跳转链接的页面(这里只使用后端的Django跳转方式,不使用前端超链接)添加代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Index</title></head><body><h2>首页</h2><hr />{% comment %} url路由来跳转 {% endcomment %}<a href="/user/user_list/">url路由跳转: 进入用户列表</a><hr />{% comment %} 反向解析来跳转 {% endcomment %}<a href="{% url 'user_list' %}">反向解析跳转: 进入用户列表</a>user_list是路由路径的name值url 是Django的模板,用于生成url<hr />{% comment %} 带命名空间的反向解析 {% endcomment %}<a href="{% url 'App:user_list' %}">带命名空间的反向解析: 进入用户列表</a></body>
</html>
- url路由跳转方式: 链接路径为 127.0.0.1:8000后面的内容
- 反向解析来跳转: 反向解析就是从 html页面(点击) -> 找到路由 -> 找到视图函数(
user_list是路由路径的name值
) - 带命名空间的反向解析: 命名空间就是
根/urls.py文件include方法
中指定的namespace
,命名空间就是为了使不同的应用之间可以使用相同的子路由路径名(例如上面的user_list)
路由传参(单个参数)
在App
的子路由中新增以下路由规则
# 详情页 <> 号内为参数传给user_detail视图函数
path('user_detail/<int:uid>/', user_detail, name='user_detail'),
定义视图函数user_detail
# 用户列表
def user_list(request):# 获取所有用户数据users = UserModel.objects.all()return render(request, 'user_list.html',{"users":users})
def user_detail(request,uid): # uid从路由参数中获取# print("uid",uid)# 获取单个用户数据user = UserModel.objects.get(pk=uid) # pk是主键primary keyreturn render(request, 'user_detail.html',{"user":user}) # 传递参数到模板中
在user_list.html文件中接收
user_list传过来的users参数,遍历(利用模板语法添加li>a标签)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>用户列表</title><style>a {text-decoration: none;}</style></head><body><h2>用户列表</h2><hr /><ul>{% for user in users %} {% comment %} 反向解析 {% endcomment %}<li><a href="{%url 'App:user_detail' user.id%}">{{user.name}} - {{user.age}}</a></li>{% endfor %}</ul></body>
</html>
所以,最终生成的a标签变成了<a href="/user/user_detail/1/">张三 - 19</a>
整个过程就是按顺序发生
- 首先用户访问user/user_list.html界面,程序调用
视图函数
获取所有用户列表并传参- 在
user_list
函数中,程序渲染本地的user_list.html
返回,在渲染的过程中,将uset_list()中获取的用户列表逐个渲染成具体的链接
- 这是对模板语法的解释
url
代表当前界面的url,App:user_detail
表示到根路由path("user/", include(("App.urls","App"), namespace="App"))
中在逐层(include(("App.urls","App")
,从应用App的urls.py子路由文件)找到名为user_detail
的路由项- 找到如下所示
path('user_detail/<int:uid>/', user_detail, name='user_detail')
- 然后
user.id
就是把id属性传给路由参数,相对于变成``path(‘user_detail/user.id/’, user_detail, name=‘user_detail’)`
路由参数支持的类型
Django支持多种类型的路由参数,常见的有:
- int:接收整数,如
<int:user_id>
。 - str:接收字符串,如
<str:username>
。 - slug:接收短横线连接的字符串,如
<slug:slug>
。 - uuid:接收UUID,如
<uuid:uuid>
。 - path:接收包含斜杠的字符串,如
<path:subpath>
。
路由传参(多参数)
视图函数
def user_view_ab(request,a,b):return HttpResponse(f"a={a},b={b}")
子路由
# 带参数的视图函数,注意,参数的名字必须和视图函数中参数的名字一致
path("user_view_ab/<int:a>/<int:b>/", user_view_ab, name="user_view_ab")
注意!!! 参数名称要对应
重定向redirect
函数
在视图函数中,可以重定向到别的网页或者路径
path('user_detail/<int:a>/',user_detail,name='userdetail'),def user_detail(a):return HttpResponse("user_detail")
# 重定向
def my_redirect(request):return redirect('http://www.baidu.com')def my_redirect2(request):return redirect('/user/user_list/')def my_redirect3(request):# reverse反向解析(根据路由name属性找到对应url)return redirect(reverse('user_list')) # 相当于 return redirect(/user/user_list/)return redirect(reverse('App:userdetail', args=(1,))) # 传参给path('user_detail/<int:a>/',user_detail,name='userdetail'),args=元组或列表,kawrgs=字典return redirect(reverse('App:userdetail', kwargs={'a':2}))
在子路由中增加重定向部分
# 用户列表(原有)
path('user_list/', user_list, name='user_list'),
path('user_detail/<int:a>/',user_detail,name='userdetail'),
# 重定向
path('myredirect/', my_redirect),
path('myredirect2/', my_redirect2),
path('myredirect3/', my_redirect3),