正确的理解和使用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实现人人网登录示例分享
Jan 19 Python
python MySQLdb Windows下安装教程及问题解决方法
May 09 Python
Python虚拟环境Virtualenv使用教程
May 18 Python
python Web开发你要理解的WSGI & uwsgi详解
Aug 01 Python
Python批量修改图片分辨率的实例代码
Jul 04 Python
flask框架配置mysql数据库操作详解
Nov 29 Python
在python中实现求输出1-3+5-7+9-......101的和
Apr 02 Python
浅析Python面向对象编程
Jul 10 Python
python删除文件、清空目录的实现方法
Sep 23 Python
python 读取串口数据的示例
Nov 09 Python
如何用Python编写一个电子考勤系统
Feb 08 Python
python 模块重载的五种方法
Apr 24 Python
编写python程序的90条建议
Apr 14 #Python
Python基础知识之变量的详解
理解深度学习之深度学习简介
Apr 14 #Python
python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析
深度学习小工程练习之垃圾分类详解
python3美化表格数据输出结果的实现代码
Apr 14 #Python
Python生成九宫格图片的示例代码
You might like
PHP使用ODBC连接数据库的方法
2015/07/18 PHP
PHP汉字转换拼音的函数代码
2015/12/30 PHP
PHP实现的随机IP函数【国内IP段】
2016/07/20 PHP
PHP聊天室简单实现方法详解
2018/12/08 PHP
jQuery图片预加载 等比缩放实现代码
2011/10/04 Javascript
通过jQuery源码学习javascript(一)
2012/12/27 Javascript
JavaScript的模块化:封装(闭包),继承(原型) 介绍
2013/07/22 Javascript
原生js操作checkbox用document.getElementById实现
2013/10/12 Javascript
jquery 页面滚动到底部自动加载插件集合
2014/01/31 Javascript
nodejs中使用多线程编程的方法实例
2015/03/24 NodeJs
JavaScript使用cookie记录临时访客信息的方法
2015/04/07 Javascript
angular2使用简单介绍
2016/03/01 Javascript
判断输入的字符串是否是日期格式的简单方法
2016/07/11 Javascript
easyui tree带checkbox实现单选的简单实例
2016/11/07 Javascript
Nodejs实现短信验证码功能
2017/02/09 NodeJs
微信小程序url传参写变量的方法
2018/08/09 Javascript
JavaScript和TypeScript中的void的具体使用
2019/09/12 Javascript
javascript网页随机点名实现过程解析
2019/10/15 Javascript
Vue通过WebSocket建立长连接的实现代码
2019/11/05 Javascript
对Python的Django框架中的项目进行单元测试的方法
2016/04/11 Python
Django中redis的使用方法(包括安装、配置、启动)
2018/02/21 Python
python 异或加密字符串的实例
2018/10/14 Python
如何使用Python实现自动化水军评论
2019/06/26 Python
使用python 的matplotlib 画轨道实例
2020/01/19 Python
python中的split、rsplit、splitlines用法说明
2020/10/23 Python
印度尼西亚最大的电商平台:Tokopedia(印尼版淘宝)
2017/12/02 全球购物
一个SQL面试题
2014/08/21 面试题
介绍一下Make? 为什么使用make
2013/12/08 面试题
医学毕业生自荐信
2013/10/11 职场文书
中医专业职业生涯规划书范文
2014/01/04 职场文书
2014年大学生就业规划书
2014/04/04 职场文书
我的梦中国梦演讲稿
2014/04/23 职场文书
学生犯错保证书
2015/05/09 职场文书
体育部部长竞选稿
2015/11/21 职场文书
浅谈pytorch中stack和cat的及to_tensor的坑
2021/05/20 Python
python脚本框架webpy模板赋值实现
2021/11/20 Python