博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django中的信号
阅读量:5741 次
发布时间:2019-06-18

本文共 7451 字,大约阅读时间需要 24 分钟。

   笔者最近遇到一个需求:

   现在需要当在数据表中的某个模型中新增一条记录后,需要将这条记录的生成信息添加到logging模块中,即每生成一条数据记录,就打印出相应的日志。笔者首先的需求是考虑使用装饰器,例如对每个执行新增记录的视图函数加上装饰器,每当执行这个视图函数时候,就先执行这个装饰器。但是这样有个弊端:例如我需要拿到当前插入到数据表中的记录,这是拿不到的!比如我想在日志中看到哪张表生成了什么样的表记录,使用装饰器是拿不到,装饰器的作用仅仅是在为当前函数添加新的功能!在执行视图函数之前要先执行装饰器,此时压根拿不到插入到数据表中的记录,另外如果这个视图函数中涉及到插入多张表中的数据,那么仅仅执行装饰器函数只能是获取到当前某一个记录,无法获取到多条记录。所以装饰器这种方法不可行。

  Django提供一种信号机制。其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) 。当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。用于在框架执行操作时解耦。

【01】Django内置的信号量

 

Model signals    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       # 请求异常后,自动触发Test signals    setting_changed             # 使用test测试修改配置文件时,自动触发    template_rendered           # 使用test测试渲染模板时,自动触发Database Wrappers    connection_created          # 创建数据库连接时,自动触发

 笔者使用最多的是post_save和post_delete两种信号,对于像update这样的操作,是不会出发信号的!我们以Django官方的例子为例来说明下信号量的使用,目前数据库中有两本书籍的记录,现在我想做的是:只要添加或者删除一条书籍记录,那就执行信号量绑定的函数,告诉我们是哪张表的记录发生了改变!

为了方便演示,我们直接将信号量相关的代码定义在应用的init文件下:

from django.db.models.signals import post_delete, post_savedef callback(sender, **kwargs):    """    carson666
{
'signal':
,'instance':
, 'created': True, 'update_fields': None, 'raw': False, 'using': 'default'}""" print("carson666") print(sender) #
print(kwargs)post_save.connect(callback) # post_save信号与callback绑定关系

其中post_save.connect(callback)的意思就是我们将信号post_save与函数callback绑定在一起,一旦检测到数据表中新增了记录,那么就执行callback函数。我们从打印结果看到,kwargs中的created为True,表示是新增一条记录。因此触发了与信号量绑定在一起的函数callback的执行。我们来看看当我们删除记录和修改记录时,它是否会改变:

def add(request):    # book_obj = Book.objects.create(title="go", price=120)  # 执行post_save信号量    # Book.objects.filter(title='linux').update(price=666)    Book.objects.get(id=2).delete()  # 执行post_delete信号量    return HttpResponse("删除书籍对象成功!!")    # return HttpResponse("创建书籍对象成功,开始触发信号")    # return HttpResponse("书籍对象价格修改成功")

最终的信号量定义如下:

from django.db.models.signals import post_delete, post_savedef callback(sender, **kwargs):    """    carson666
{
'signal':
,'instance':
, 'created': True, 'update_fields': None, 'raw': False, 'using': 'default'} :param sender: :param kwargs: :return: """ print("carson666") print(sender) #
print(kwargs)def delete_success(sender, **kwargs): print("删除书籍对象成功,信号量执行")post_save.connect(callback) # post_save信号与callback绑定关系post_delete.connect(delete_success)

另外在上面打印的kwargs中,我们重点关注两个参数:instance,表示我们创建的实例对象,另外一个参数就是created参数,表示是否是新建实例对象。理解这两个参数很重要,后面我们将会进行具体案例的解析。

【02】信号量的使用方式二:

from django.db.models.signals import post_savefrom django.dispatch import receiver@receiver(post_save, sender=Book)def my_callback(sender, **kwargs):    print("Request finished!")

【03】Django信号量结合DRF的实际使用举例

笔者在真实项目中就使用了信号量来解决实际的问题。

场景一:利用Django信号量来修改用户的密码。

例如用户使用手机号码注册的时候,传递过来的是手机号码,明文密码,现在我们肯定需要对密码加密,因此就可以使用Django的信号量:

定义一个signals.py文件:

# -*- coding: utf-8 -*-from django.db.models.signals import post_savefrom django.dispatch import receiverfrom django.contrib.auth import get_user_modelUser = get_user_model()# 使用django信号量实现用户密码修改"""sender表示接受哪个model传递过来的另外还需要判断一下这个created参数是否为True,表示是否是新建用户的时候这里可以让代码的分离性比较好,推荐使用Django信号量"""@receiver(post_save, sender=User)def create_user(sender, instance=None, created=False, **kwargs):    if created:        # instance就是我们的user对象        password = instance.password        instance.set_password(password)        instance.save()

然后在apps.py中,在ready函数中导入信号量:

使用场景二

需求:我们通常会使用淘宝或者京东购物,简单的购物车功能中,当用户收藏了某件商品,那么回创建一个用户收藏商品对象;同时在商品表中,商品的收藏数就要加1;如果用户取消收藏了该商品,那么对应商品的收藏数就要减一。这个就可以使用Django中的信号量解决,先来看看两张数据表,商品表:

class Goods(models.Model):    """    商品    注意这里的category指向了第三级类别,表示这个商品属于哪个类别    我们这里总共有三个类别    """    category = models.ForeignKey(GoodsCategory, verbose_name="商品类目")    goods_sn = models.CharField(max_length=50, default="", verbose_name="商品唯一货号")    name = models.CharField(max_length=100, verbose_name="商品名")    click_num = models.IntegerField(default=0, verbose_name="点击数")    sold_num = models.IntegerField(default=0, verbose_name="商品销售量")    fav_num = models.IntegerField(default=0, verbose_name="收藏数")    goods_num = models.IntegerField(default=0, verbose_name="库存数")    market_price = models.FloatField(default=0, verbose_name="市场价格")    shop_price = models.FloatField(default=0, verbose_name="本店价格")    goods_brief = models.TextField(max_length=500, verbose_name="商品简短描述")    goods_desc = UEditorField(verbose_name=u"内容", imagePath="goods/images/", width=1000, height=300,                              filePath="goods/files/", default='')    ship_free = models.BooleanField(default=True, verbose_name="是否承担运费")    goods_front_image = models.ImageField(upload_to="goods/images/", null=True, blank=True, verbose_name="封面图")    is_new = models.BooleanField(default=False, verbose_name="是否新品")    is_hot = models.BooleanField(default=False, verbose_name="是否热销")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = '商品'        verbose_name_plural = verbose_name    def __str__(self):        return self.name
View Code

用户收藏表:

class UserFav(models.Model):    """    用户收藏    """    user = models.ForeignKey(User, verbose_name="用户")    goods = models.ForeignKey(Goods, verbose_name="商品", help_text="商品id")    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加时间")    class Meta:        verbose_name = '用户收藏'        verbose_name_plural = verbose_name        unique_together = ("user", "goods")  # 设置联合唯一主键    def __str__(self):        return self.user.username

也就是说一旦UserFav这张表中新增一条记录,那么对应goods表中的收藏数fav_num就要+1,来看看这个信号量是怎么定义的:

# -*- coding: utf-8 -*-from django.db.models.signals import post_save, post_deletefrom django.dispatch import receiverfrom user_operation.models import UserFav@receiver(post_save, sender=UserFav) # 这个信号的意思就是一旦UserFav这张表中新增一条记录,那么post_save监测到这个信号,那就直接执行对应的绑定函数 # create_userfavdef create_userfav(sender, instance=None, created=False, **kwargs):    if created:        """        当用户创建了用户收藏商品对象后,才将商品的收藏数目+1        """        # instance就是我们的UserFav实例对象        goods = instance.goods        goods.fav_num += 1        goods.save()

同理,如果用户取消收藏商品,那么商品的收藏数目就要减一,如下:

# 用户取消收藏某件商品,那么商品的收藏数就要减1@receiver(post_delete, sender=UserFav)def delete_userfav(sender, instance=None, created=False, **kwargs):    goods = instance.goods    goods.fav_num -= 1    goods.save()

使用方法如下:

以上就是Django信号量结合DRF的实践场景!欢迎评论和学习!

参考资料:

【01】http://sabinemaennel.ch/django/signals-in-django/

【02】https://docs.djangoproject.com/en/1.10/topics/signals/
【03】http://www.weiguda.com/blog/38/
【04】http://www.python88.com/topic/151
【05】https://pylixm.cc/posts/2017-01-24-Django-signal.html

 

转载于:https://www.cnblogs.com/pyspark/p/8343509.html

你可能感兴趣的文章
Java判断是否为垃圾_Java GC如何判断对象是否为垃圾
查看>>
多项式前k项和java_多项式朴素贝叶斯softmax改变
查看>>
java数组只能交换0下标和n_编程练习-只用0交换排序数组
查看>>
java的maxrow_聊聊pg jdbc statement的maxRows参数
查看>>
centos7安装mysql视频教程_centos7安装mysql(完整)
查看>>
php图片赋值,php如何优雅地赋值
查看>>
dz.27z.co index.php,dz7.2 伪静态规则
查看>>
如何解决OutOfMemoryError
查看>>
【探索HTML5第二弹01】HTML5的前世今生以及来世
查看>>
Failed to connect to remote VM. Connection refused. Connection refused: connect
查看>>
freeze
查看>>
JS时间转时间戳,时间戳转时间。时间显示模式。
查看>>
SAP HANA存储过程结果视图调用
查看>>
设计模式 ( 十八 ):State状态模式 -- 行为型
查看>>
OracleLinux安装说明
查看>>
nova分析(7)—— nova-scheduler
查看>>
hive 权限:Authorization failed:No privilege 'Create' found for outputs .
查看>>
HDU1007 Quoit Design
查看>>
Memcached安装
查看>>
MVVM中的命令绑定及命令参数
查看>>