正确的理解和使用Django信号(Signals)


Posted in Python onApril 14, 2021

Django 提供一个了“信号分发器”机制,允许解耦的应用在框架的其它地方发生操作时会被通知到。 通俗而讲Django信号的工作原理就是当某个事件发生的时候会发出一个信号(signals), 而监听这个信号的函数(receivers)就会立即执行。Django信号的应用场景很多,尤其是用于不同模型或程序间的联动。常见例子包括创建User对象实例时创建一对一关系的UserProfile对象实例,或者每当用户下订单时触发给管理员发邮件的动作。今天小编我就分享下如何正确使用Django的信号(signals)。

Django信号的一个简单例子

假设我们有一个如下User模型,我们希望每次有User对象新创建时都打印出有新用户注册的提示信息,我们可以使用Django信号(signals)轻松实现。我们的信号发送者sender是User模型,每当User模型执行post_save动作时就会发出信号。此时我们自定义的create_user函数一旦监听到User发出的post_save信号就会执行,先通过if created判断对象是新创建的还是被更新的;如果对象是新创建的,就会打印出提示信息。

# models.py

from django.db import models

from django.db.models import signals
from django.dispatch import receiver

class User(models.Model):
    name = models.CharField(max_length=16)
    gender = models.CharField(max_length=32, blank=True)

def create_user(sender, instance, created, **kwargs):

    if created:

        print("New user created!")

post_save.connect(create_user, sender=User)

在上例中我们使用了信号(post_save)自带的connect的方法将自定义的函数与信号发出者(sender)User模型进行了连接。在实际应用中一个更常用的方式是使用@receiver装饰器实现发送者与监听函数的连接,如下所示。@receiver(post_save, sender=User)读起来的意思就是监听User模型发出的post_save信号。

from django.db import models

from django.db.models.signals import post_save
from django.dispatch import receiver

class User(models.Model):
    name = models.CharField(max_length=16)
    gender = models.CharField(max_length=32, blank=True)

@receiver(post_save, sender=User)
def create_user(sender, instance, created, **kwargs):

    if created:

        print("New user created!")

利用Django信号实现不同模型的联动更新

我们再来看一个复杂一点的例子。我们有一个Profile模型,与User模型是一对一的关系。我们希望创建User对象实例时也创建Profile对象实例,而使用post_save更新User对象时不创建新的Profile对象。这时我们就可以自定义create_user_profile和save_user_profile两个监听函数,同时监听sender(User模型)发出的post_save信号。由于post_save可同时用于模型的创建和更新,我们用if created这个判断来加以区别。

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    birth_date = models.DateField(null=True, blank=True)

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
   if created:
       Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

Django常用内置信号

之前的例子中我们使用的都是post_save信号,即在模型调用save()方法后才发送信号。Django其它常用内置信号还包括:

  • django.db.models.signals.pre_save & post_save在模型调用 save()方法之前或之后发送。
  • django.db.models.signals.pre_init& post_init在模型调用_init_方法之前或之后发送。
  • django.db.models.signals.pre_delete & post_delete在模型调用delete()方法或查询集调用delete() 方法之前或之后发送。
  • django.db.models.signals.m2m_changed在模型多对多关系改变后发送。
  • django.core.signals.request_started & request_finished Django建立或关闭HTTP 请求时发送。

如何正确放置Django信号的监听函数代码

在之前案例中,我们将Django信号的监听函数写在了models.py文件里。当一个app的与信号相关的自定义监听函数很多时,此时models.py代码将变得非常臃肿。一个更好的方式把所以自定义的信号监听函数集中放在app对应文件夹下的signals.py文件里,便于后期集中维护。

假如我们有个account的app,包含了User和Pofile模型,我们不仅需要在account文件夹下新建signals.py,还需要修改account文件下apps.py和__init__.py,以导入创建的信号监听函数。

# account/signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import User, Profile



@receiver(post_save, sender=User)

def create_user_profile(sender, instance, created, **kwargs):

  if created:

      Profile.objects.create(user=instance)



@receiver(post_save, sender=User)

def save_user_profile(sender, instance, **kwargs):

    instance.profile.save()

# account/apps.py

from django.apps import AppConfig

class AccountConfig(AppConfig):
    name = 'account'

    def ready(self):
        import account.signals

# account/__init__.py

default_app_config = 'account.apps.AccountConfig'

小结

在本文里我们总结了Django信号(signals)的工作原理,介绍了如何使用Django信号实现模型或程序的联动。最后我们还总结了Django常用内置信号以及如何正确放置自定义的信号监听函数。欢迎关注我们更多Python Web开发和Django原创文章。

以上就是正确的理解和使用Django信号(Signals)的详细内容,更多关于Django信号(Signals)的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python实现在无须过多援引的情况下创建字典的方法
Sep 25 Python
详解Python的Flask框架中生成SECRET_KEY密钥的方法
Jun 07 Python
Python3.5编程实现修改IIS WEB.CONFIG的方法示例
Aug 18 Python
Python编程产生非均匀随机数的几种方法代码分享
Dec 13 Python
Python cookbook(数据结构与算法)从字典中提取子集的方法示例
Mar 22 Python
Python使用win32 COM实现Excel的写入与保存功能示例
May 03 Python
解决pycharm 误删掉项目文件的处理方法
Oct 22 Python
python 求一个列表中所有元素的乘积实例
Jun 11 Python
pycharm重命名文件的方法步骤
Jul 29 Python
解决python -m pip install --upgrade pip 升级不成功问题
Mar 05 Python
Python函数参数分类原理详解
May 28 Python
python cv2.resize函数high和width注意事项说明
Jul 05 Python
编写python程序的90条建议
Apr 14 #Python
Python基础知识之变量的详解
理解深度学习之深度学习简介
Apr 14 #Python
python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析
深度学习小工程练习之垃圾分类详解
python3美化表格数据输出结果的实现代码
Apr 14 #Python
Python生成九宫格图片的示例代码
You might like
php mssql 时间格式问题
2009/01/13 PHP
用PHP ob_start()控制浏览器cache、生成html实现代码
2010/02/16 PHP
PHP随机数生成代码与使用实例分析
2011/04/08 PHP
windows下配置php5.5开发环境及开发扩展
2014/12/25 PHP
PHP中单例模式与工厂模式详解
2017/02/17 PHP
Linux下快速搭建php开发环境
2017/03/13 PHP
jquery 最简单的属性菜单
2009/10/08 Javascript
javascript的字符串按引用复制和传递,按值来比较介绍与应用
2012/12/28 Javascript
自己动手实现jQuery Callbacks完整功能代码详解
2013/11/25 Javascript
带左右箭头图片轮播的JS代码
2013/12/18 Javascript
Node.js实用代码段之获取Buffer对象字节长度
2016/03/17 Javascript
JavaScript DOM节点操作方法总结
2016/08/23 Javascript
MUI  Scroll插件的使用详解
2017/04/13 Javascript
DataTables添加额外的查询参数和删除columns等无用参数实例
2017/07/04 Javascript
Vue实例中生命周期created和mounted的区别详解
2017/08/25 Javascript
vue+swiper实现组件化开发的实例代码
2017/10/26 Javascript
JavaScript常见JSON操作实例分析
2018/08/08 Javascript
解决vue接口数据赋值给data没有反应的问题
2018/08/27 Javascript
详解react阻止无效重渲染的多种方式
2018/12/11 Javascript
JS实现数组删除指定元素功能示例
2019/06/05 Javascript
Vue.set 全局操作简单示例
2019/09/19 Javascript
20多个小事例带你重温ES10新特性(小结)
2019/09/29 Javascript
js实现鼠标拖曳效果
2020/12/30 Javascript
Vue中的nextTick作用和几个简单的使用场景
2021/01/25 Vue.js
python 定时修改数据库的示例代码
2018/04/08 Python
TensorFlow损失函数专题详解
2018/04/26 Python
Python3实现将本地JSON大数据文件写入MySQL数据库的方法
2018/06/13 Python
使用Pandas的Series方法绘制图像教程
2019/12/04 Python
借助Paramiko通过Python实现linux远程登陆及sftp的操作
2020/03/16 Python
北京RT科技有限公司.net工程师面试题
2013/02/15 面试题
中国梦的演讲稿
2014/01/08 职场文书
2014红色之旅心得体会
2014/10/07 职场文书
优秀班主任工作总结2015
2015/05/25 职场文书
运动会运动员赞词
2015/07/22 职场文书
SQL试题 使用窗口函数选出连续3天登录的用户
2022/04/24 Oracle
Nginx静态压缩和代码压缩提高访问速度详解
2022/05/30 Servers