多级字典表单的Python实现
在真实的企业生产环境中,我们会遇到各种各样的需求,比如对客户端请求进行过滤,将满足某些条件的客户端请求过滤掉,这时我们可以利用Django的中间件来实现该需求;或者,我希望每次model的save()方法被调用前后,都要写一条日志到日志文件中,而此时我们可以通过Django提供的内置信号post_save来实现,本文介绍一下Django的高级功能——信号。
“信号分发器”允许解耦的应用在框架的其它地方发生操作时会被通知到。 简单来说,信号允许特定的sender通知一组receiver某些操作已经发生。 这在多处代码和同一事件有关联的情况下很有用。
信号的概念
Django2.1官文对signal的解释如下:
Django includes a "signal dispatcher" which helps allow decoupled applications get notified when actions occur elsewhere in the framework.
In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place.
They're especially useful when many pieces of code may be interested in the same events.
翻译过来就是:Django框架内部包含了一个信号调度器,它的作用是可以将框架内部发生的任何操作都通知到功能独立的应用程序,当然,我们也可以缩小发送者和接收者的范围,即指定具体的发送者和接受者,假设我们的程序中有多个业务逻辑都在等待某一个事件发生之后再继续执行后面的代码,那么此时,信号是非常有用的。
Django内置的信号
Django内置的信号如下(加粗的是比较常用的):
Model signals
pre_init # django的model执行其构造方法前,自动触发
post_init # django的model执行其构造方法后,自动触发
pre_save # django的model对象保存前,自动触发
post_save # django的model对象保存后,自动触发
pre_delete # django的model对象删除前,自动触发
post_delete # django的model对象删除后,自动触发
m2m_changed # django的model中使用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 # 请求异常后,自动触发
Test signals
setting_changed # 使用test测试修改配置文件时,自动触发
template_rendered # 使用test测试渲染模板时,自动触发
Database Wrappers
connection_created # 创建数据库连接时,自动触发
Django内置信号的使用
注册内置信号
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数。注册信号,写入与project同名的文件夹下的_init_.py文件中,也是换数据库引擎的地方。

如上图,项目名为signalTest,我们在与项目同名的包的__init__.py文件中注册Django内置的信号,然后使用就可以了。
监听信号的两种方式
方式一:直接监听
def my_callback(sender, **kwargs):
print("Request finished!")
from django.core.signals import request_finished request_finished.connect(my_callback)
方式二:使用装饰器监听
def my_callback(sender, **kwargs):
print("Request finished!")
from django.core.signals import request_finished
from django.dispatch import receiver @receiver(request_finished)
def my_callback(sender, **kwargs):
print("Request finished!")
注册时指定发送者
from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel # 在MyModel对应的数据保存前执行my_handler函数
@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
xxx
注册完内置信号后,只要满足触发条件,对应的函数会在相应的条件下去执行,不用人手动去调用。
内置信号详细介绍 ***
更多内置信号的说明请参考这篇博客:https://www.cnblogs.com/liwenzhou/p/9745331.html
自定义信号的使用 *****
首先要知道的是,我们用的信号都是django.dispatch.Signal这个类的实例。
首先定义信号
在任意的py文件中定义信号:
import django.dispatch
signal_done = django.dispatch.Signal(providing_args=["height", "width"])
然后在与项目同名的包的__init__文件中注册信号
def callback(sender, **kwargs):
print("callback")
print(sender,kwargs) signal_done.connect(callback)
最后在需要触发信号的地方使用自定义信号
from 路径 import signal_done signal_done.send(sender='Naruto',height=123, width=456)
最后需要注意:由于内置信号的触发者已经集成到Django中,所以其会自动调用;而对于自定义信号则需要开发者在对应位置指定触发。
在路由分发前注册信号的方法 *****
上面介绍的一种方式是在项目同名的包的__init__.py文件中去注册信号。
我们也可以利用Django在路由分发之前做一下信号的注册操作。
这里用到了Django启动的机制:django.dispatch.Signal在django.setup()的过程中,它会遍历settings.INSTALLED_APPS列表中的每一项,并调用该AppConfig的ready方法,因此,将recevier订阅signal的过程放置于ready方法中就能保证该代码的执行。
我们来拿一个具体的项目为例。
一、项目的目录结构如下

(1)把所有的信号都写在了signals包中,并且signals包中的__init__.py文件中实例化Signal类的对象(注意Python在import一个包的时候会执行里面的__init__文件),执行的操作我写在了handlers.py文件中;
(2)然后,利用Django的启动的原理,我把信号的注册写在了apps.py的SignalappConfig类的ready方法中,保证在路由分发之前就注册自定义的信号。
二、注册信号的具体写法
signals/__init__.py:
# -*- coding:utf-8 -*-
from django.dispatch import Signal my_signal = Signal(providing_args=[])
signals/handlers.py:
# -*- coding:utf-8 -*- def my_callback(sender,**kwargs):
print('my_callback...')
signalapp/apps.py
from django.apps import AppConfig # 从外部导入自定义信号及处理的函数
from signals import my_signal
from signals.handlers import my_callback class SignalappConfig(AppConfig):
name = 'signalapp' def ready(self):
# 注册信号
my_signal.connect(my_callback)
三、使用自定义的信号
做一个简单的路由与视图测试一下这个自定义的信号是否成功:
signalTest/urls.py:
from django.contrib import admin
from django.urls import path from signalapp import views urlpatterns = [
path('admin/', admin.site.urls), path('index/',views.index,name='index'),
]
sjgnalapp/views.py:
from django.shortcuts import render,HttpResponse # 导入自定义信号的处理函数
from signals.handlers import my_callback def index(request): # 使用自定义信号
my_callback(sender='index')
return HttpResponse('OK')
启动Django程序后我们在浏览器中输入127.0.0.1:8000/index,可以看到在后台打印出了自定义信号处理函数中所打印的数据:
my_callback...
定制信号的发送者
默认情况下,某些信号会被多次发送,但是,通常,我们只希望接收某个或者某些特定的发送者发出的信号,比如说django.db.models.signals.pre_saves,该信号,它在每个model的save()方法被执行的时候被发送,不过,很多情况下,我们只想记录某个特定的model的save()方法被执行时的日志。
在上述情况下,我们可以指定只接受我们指定的信号发送者发出的信号。
还是用django.db.models.signals.pre_saves举例,下面我们来演示如何指定发送者
from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel @receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
xxx
断开信号
如果不希望再接收某个信号,我们可以调用Signal.disconnect()方法。
更多内容详见官网文档
多级字典表单的Python实现的更多相关文章
- flask 使用Flask-WTF处理表单
使用Flask-WTF处理表单 扩展Flask-WTF继承了WTFforms,使用它可以在flask中更方便的使用WTForms.Flask-WTF将表单数据解析.CSRF保护.文件上传等功能与Fla ...
- 【Python】django表单与提交
参考:http://djangobook.py3k.cn/2.0/chapter07/ 本文的内容应属于django的表单模块,没有涉及到的后端request对象的处理方法可以单独深入学习表单. UR ...
- Python+Django+SAE系列教程11-----request/pose/get/表单
表单request,post,get 首先我们来看看Request对象,在这个对象中包括了一些实用的信息,学过B/S开发的人来说这并不陌生,我们来看看在Django中是怎样实现的: 属性/方法 说明 ...
- Python Tornado初学笔记之表单与模板(一)
Tornado中的表单和HTML5中的表单具有相同的用途,同样是用于内容的填写.只是不同的是Tornado中的表单需要传入到后台,然后通过后台进行对模板填充. 模板:是一个允许嵌入Python代码片段 ...
- python自动化开发-[第二十天]-form表单,CBV和FBV,序列化
1.CBV和FBV的用法 2.序列化用法 3.form表单 一.CBV和FBV 1.cbv是 class based view(基于类),fbv是function based view(基于函数) 2 ...
- python 全栈开发,Day111(客户管理之 编辑权限(二),Django表单集合Formset,ORM之limit_choices_to,构造家族结构)
昨日内容回顾 1. 权限系统的流程? 2. 权限的表有几个? 3. 技术点 中间件 session orm - 去重 - 去空 inclusion_tag filter 有序字典 settings配置 ...
- Python的Django框架中forms表单类的使用方法详解
用户表单是Web端的一项基本功能,大而全的Django框架中自然带有现成的基础form对象,本文就Python的Django框架中forms表单类的使用方法详解. Form表单的功能 自动生成HTML ...
- 巨蟒python全栈开发django11:ajax&&form表单上传文件contentType
回顾: 什么是异步? 可以开出一个线程,我发出请求,不用等待返回,可以做其他事情. 什么是同步? 同步就是,我发送出了一个请求,需要等待返回给我信息,我才可以操作其他事情. 局部刷新是什么? 通过jq ...
- Python学习笔记整理总结【Django】【MVC/MTV/路由分配系统(URL)/视图函数 (views)/表单交互】
一.Web框架概述 Web框架本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. #!/usr/bin/env python # -*- coding:utf-8 ...
随机推荐
- 下载B站、秒拍等视频网站视频
需要一个FVD Downloader(插件) 安装过程很简单,会浏览器安装插件的就不多说了!
- 【spring源码分析】spring关于循环依赖的问题
引言:循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错.下面说一下Spring是如果解决循环依赖的. 第一种: ...
- Mybatis一(基础)
mybatis架构 1.mybatis配置 SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息. mapper.xml文件即sql映射文件, ...
- 打印流-PrintStream和PrintWriter
概念: 打印流是输出信息最方便的类,注意包含PrintStream(字节打印流)和 PrintWriter(字符打印流).打印流提供了非常方便的打印功能,可以打印任何类型的数据信息,例如:小数,整数, ...
- 对象的释放Dispose和Close对比
C#内存释放的几个方法对比: 而Close与Dispose这两种方法的区别在于,调用完了对象的Close方法后,此对象有可能被重新进行使用:而Dispose方法来说,此对象所占有的资源需要被标记为无用 ...
- Docker网络解决方案-Flannel(转)
转自https://www.cnblogs.com/kevingrace/p/6859114.html Docker跨主机容器间网络通信实现的工具有Pipework.Flannel.Weave.Ope ...
- koa 学习资料
koa 学习资料 学习资料 地址 koa 中文版 https://koa.bootcss.com/
- python 术语
python 术语 术语英文 术语中文 说明 PyPI(Python Package Index) 搜索python包的网站:https://pypi.org/ pip.easy_install 包管 ...
- requestAnimationFrame 知识点
与setTimeout相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机.具体一点讲,如果屏幕刷新率是60Hz,那么回调函数就每16.7ms被执行一次,如果刷新 ...
- NET设计模式 第二部分 结构性模式(9):装饰模式(Decorator Pattern)
装饰模式(Decorator Pattern) ——.NET设计模式系列之十 Terrylee,2006年3月 概述 在软件系统中,有时候我们会使用继承来扩展对象的功能,但是由于继承为类型引入的静态特 ...