django无名分组/反向解析/路由分发

django请求生命周期流程图

当客户端浏览器访问django后端时django框架中发生了哪些事情呢?

客户端请求服务端时将客户端请求的各种数据和信息进行整理。应用程序则负责具体的逻辑处理。

1.用户在浏览器输入url 发送一个get方法的request请求

2.django中封装了socket的wsgi服务器,监听端口接收request请求

3.初步封装后传入中间件,中间件处理后再传入路由分发 匹配对应视图函数

4.再将request请求传输到views中的视图函数进行业务逻辑处理

5.再调用modles中表对象,通过orm拿到数据库的数据

6.然后对templates中对应的模版进行渲染,封装模版再次传入中间件

7.中间键处理完成后再通过wsgi再进行封装处理,响应给浏览器展示
image

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)
posted @   Python-moon  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示