django无名分组/反向解析/路由分发
django请求生命周期流程图
当客户端浏览器访问django后端时django框架中发生了哪些事情呢?
客户端请求服务端时将客户端请求的各种数据和信息进行整理。应用程序则负责具体的逻辑处理。
1.用户在浏览器输入url 发送一个get方法的request请求
2.django中封装了socket的wsgi服务器,监听端口接收request请求
3.初步封装后传入中间件,中间件处理后再传入路由分发 匹配对应视图函数
4.再将request请求传输到views中的视图函数进行业务逻辑处理
5.再调用modles中表对象,通过orm拿到数据库的数据
6.然后对templates中对应的模版进行渲染,封装模版再次传入中间件
7.中间键处理完成后再通过wsgi再进行封装处理,响应给浏览器展示
django路由层
1.路由匹配
urls.文件中:
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', user_info.views.login),
path('home/', user_info.views.home),
path('register/', user_info.views.register),
]
django2.x及以上 path 第一个参数写什么就匹配什么
django1.x第一个参数使用的是正则表达式
无论什么版本 用户访问django项目时都会自带在url后加/后缀的功能
配置文件中 写入 APPEND_SLASH = False 可以手动取消 但不建议
2.正则匹配
urls.文件中:
urlpatterns = [
path('admin/', admin.site.urls),
re_path('^$',user_info.views.home)
# 首页正则
re_path('^login/', user_info.views.login),
]
re_path后面可以直接跟正则表达式 可以用用户输入的路由中进行匹配,只要匹配到了 就会停止对其他 会立即执行对应的视图函数
django老版本中是 url() 新版本是 re_path()
3.无名分组与有名分组
urls.文件中:
urlpatterns = [
re_path('^$',user_info.views.home)
re_path('^login/', user_info.views.login),
re_path('^test/(\d+)/', user_info.views.login),
]
def login(request,test):
print(test)
# 正则匹配会将括号内匹配到的内容,当作位置参数传递给后面的视图函数
有名分组
urlpatterns = [
re_path('^$',user_info.views.home)
re_path('^login/', user_info.views.login),
re_path('^test/(?P<id>\d+)/', user_info.views.login),
]
def login(request,id):
print(id)
可以给正则命名 (?P<别名>正则表达式)
这样正则表达式匹配到的数字会被当作关键字传参 传给视图函数
无名分组和有名参数不可以混合使用
但是可以同时使用多个
urlpatterns = [
re_path('^test/(?P<id>\d+)/(?P<num>\d{4})',
user_info.views.login),
]
4.转换器
urls.文件中:
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', user_info.views.login),
path('home/<str:info>', user_info.views.home),
path('register/<int:id>', user_info.views.register),
]
<str:info> 匹配除路径分隔符外的任何字符
<int:id> 匹配任意正整数
<slug:num> 匹配任意一个由字母或数字组成的字符串
<uuid:uuid> 匹配格式化后的uuid
<path:url> 匹配完整的url
def login(request,info):
print(info)
home(实参request对象,info='转换器匹配到的数据')
register(request,id='转换器匹配到的数据')
无名反向解析
path('login/', user_info.views.login),
通过一些方法得到一个结果 该结果可以直接访问对应的url触发视图函数
我们要实现 url 动态获取
path('login/', user_info.views.login,name='log'),
第一步:先给路由和视图起别名
1.前端反向解析
{% url 别名%}
<a href:"{% url 'log'%}">111</a>
通过别名绑定 这样无论怎么更改 别名不变都可以实现对应视图函数
2.后端反向解析
from django.shortcuts imput render,reverse
def login(request):
reverse('别名')
就可以拿到路由的名字
有名无名分组反向解析
urls.文件中:
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', user_info.views.login),
path('home/(\d+)', user_info.views.home,nmae='xxx'),
# 无名分组的反向解析
path('^login$',user_info.views.login)
]
前端
{% url 'xxx' 123 %}
# 输入别名 然后需要传一个符合分组正则的数据
def home(request,args):
reverse('xxx',args=(123,))
# 输入别名 然后需要传一个符合分组正则的数据
return render(request,'login.html')
这个数字一般情况放的是数据的主键值 利用主键值来编辑数据
设置一个无名分组的路径 起好别名
当需要跳转这个路径的时候,可以使用
<a href="{% url 'update' user.id %}" class="btn btn-primary">编辑</a>
跳转到别名为 update 页面 并路由对应函数传参user.views.update(id)
有名分组反向解析
path('home/(?P<别名>\d+)',user.views.func,name='xxx'),
前端语法:{% url 'xxx' 123 %}
def home(request):
reverse('xxx',args=(123,))
代码说明
urlpatterns = [ path('add/', user.views.add_user),
re_path('delete/(\d+)', user.views.delete,name='delete'),
#设置一个无名分组 deletes视图函数可以接受传参(\d+) 起别名为 'delete'
re_path('update/(\d+)',user.views.update,name='update'),
re_path('^$', user.views.home,name='home'), ]
<a href="{% url 'update' user.id %}" class="btn btn-primary">编辑</a>
<a href="{% url 'delete' user.id %}" class="btn btn-danger a1">删除</a>
# 跳转到路由别名为 delete的页面 触发对应函数 传参为 user.id
{% url 'update' user.id %}
跳转到别名为 update 页面 并传参 user.views.update(id)
{% url 'xxx' 123 %}
# 输入别名 然后需要传一个符合分组正则的数据
直接通过 反向解析跳转页面并传递参数
路由分发
Django中每一个app都有自己的templates文件夹 urls.py static文件等
正因为这个特点 django能够非常好的进行分组开发 每个人只写自己的app
最后利用路由分发的特点将所有app文件整合起来
根目录下的urls.py为总路由
在自己的app里面创建urls.py
app01.urls.py 子路由
from django.urls import path,re_path
from app01 import views
# 子路由正常写就可以了
urlpatterns = [ path('login/', views.login) ]
django.urls.py 总路由
利用路由分发机制识别当前url属于哪个app下面的 然后分发给对应的app处理
关键词:include 需要导入这个模块
from django.contrib import admin
from django.urls import path,include,re_path
urlpatterns = [
path('admin/', admin.site.urls),
re_path('^app01/',include('app01.urls')),
re_path('^app02/',include('app02.urls')),
re_path('^app03/',include('app03.urls')),
]
# 路由先匹配app的名字 然后再发送给对应app的路由中执行
# 千万不能加$符 只匹配头部即可
名称空间
当多个应用代码里出现了同样的路由别名。会导致后端反向解析错误。
app01 urls.py
urlpatterns = [ path('login/', views.login, name='login') ]
app02 urls.py
urlpatterns = [ path('login/', views.login, name='login') ]
解决方式一:
在总路由设置 namespace='名称空间'
urlpatterns =
[ re_path('^app01/', include('app01.urls'),namespace='app01'),
re_path('^app02/', include('app02.urls'),namespace='app02') ]
后端反向解析: reverse('app01:login') reverse('app02:login')
前端反向解析:{% url 'app01:login' %} {% url 'app02:login' %}
解决方式二:
避免名称冲突,
#子路由内路由别名 定义的时候最好加上app前缀,这样所有子路由的别名都不会重复
# 反向解析也就不会出现名称空间问题
app01 urls.py
urlpatterns = [ path('login/', views.login, name='app01_login') ]
app02 urls.py
urlpatterns = [path('login/', views.login, name='app02_login')]
在写自己的app时 在起别名时加上前缀
name='app01_login' name='app02_login'
后端反向解析: reverse('app01_login') reverse('app02_login')
前端反向解析:{% url 'app01_login' %} {% url 'app01_login' %}
django中的信号
django内置信号
用于在框架中解藕 降低代码侵入性
pre_init # django的modal执行其构造方法前,自动触发
post_init # django的modal执行其构造方法后,自动触发
pre_save # django的modal对象保存前,自动触发
post_save # django的modal对象保存后,自动触发
pre_delete # django的modal对象删除前,自动触发
post_delete # django的modal对象删除后,自动触发
m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
Request/response signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
Database Wrappers
connection_created # 创建数据库连接时,自动触发
1.写一个函数
def callBack(*args, **kwargs):
print(args)
print(kwargs)
2.绑定信号
from django.db.models.signals import pre_save
post_save.connect(callBack)
# 对象保存后,自动触发
# 只要对象进行了seve操作 就会触发这个信号 执行对象的函数
3.等待触发
也可以解决双写一致性的问题,当表中的数据被修改时,就触发一个信号将修改的数据同步到
redis当中
自定义信号
定义信号(一般创建一个py文件)(toppings,size 是接受的参数)
1.创建信号
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
# pizza_done信号名 可以任意取。 (是否需要参数)
2.编写函数 绑定信号
def callback(sender, **kwargs):
print("callback")
print(sender,kwargs)
pizza_done.connect(callback)
3.任意地方导入信号 然后触发信号
from 路径 import pizza_done
pizza_done.send(sender='seven',toppings=123, size=456)
分类:
Django教程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了