• Django信号


    Django信号

    在开发过程中,可能有写情况没有考虑进去,突然想新增一些行为,这时不想改变原始接口,怎么对这些接口进行扩展呢

    • Django为我们提供了一种信号处理的方式,通过监听某个model的行为,然后触发我们希望预期执行的效果

    先看一个简单的例子

    这里假设读者已经掌握了如果创建模型,以及对模型的一些基本的操作

    我们通过IDE或命令创建好的Django项目结构大概都是这样的

    
    项目名
    |__app
    |__|__apps.py
    |__|__admin.py
    |__|__tests.py
    |__|__models.py
    |__|__views.py
    |__|__...
    
    
    • 假设这是最初设计的model,我们根据这个model写了一些接口
    • models.py
    from django.db import models
    class Category(models.Model):
        name = models.CharField(max_length=255, verbose_name='类名')
        builtin = models.BooleanField(verbose_name='内置属性', blank=True,
                                      default=False)
        index = models.IntegerField(verbose_name='索引', blank=True, null=True,
                                    default=1)
    
        class Meta:
            verbose_name = '类目'
            verbose_name_plural = '类目'
            db_table = 'category'
    
    • 现在业务需求变了,我们需要对model新增一个类型字段
    • models.py
    from django.db import models
    class Category(models.Model):
        name = models.CharField(max_length=255, verbose_name='类名')
        builtin = models.BooleanField(verbose_name='内置属性', blank=True,
                                      default=False)
        type = models.CharField(max_length=255, verbose_name='类型', blank=True, null=True)
        index = models.IntegerField(verbose_name='索引', blank=True, null=True,
                                    default=1)
    
        class Meta:
            verbose_name = '类目'
            verbose_name_plural = '类目'
            db_table = 'category'
    
    • 假设有两种类型,A和B,我们希望给所有之前的数据都使用默认类型A。新增的数据使用新类型B

    这个时候,你可能想说,直接改表结构不就行了,

    好吧,我们换个方式,当我们改变类型时,还需要触发一些其它行为,比如通知某些人

    我们先看下实现过程

    • 首先我们得在settings注册app,
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app',  # 新注册的app,通常这样也能用
    ]
    

    再创建一个监听触发行为的模块signal.py

    """
    这里我只举个例子,还有更多类型的信号,都在在signals模块里找到,也可以自定义,参照里面的已定义好的信号方式定义就行
    通常自带的信号都是Django自动会帮我们触发的,这个自动不是说任何时候随意的触发,而是只在我们期望的事件发生时才触发该信号
    post_init 通常是在model已经执行了__init__方法之后才触发的行为,对应的就有prev_init,初始化之前触发的行为
    选这个post_init信号是因为我们希望用户只是在查看才去检查这个model类型,因为如果用户是去修改的话,我们其实已经在修改过程处理好了这个类型
    """
    from app.models import Category
    from django.db.models.signals import post_init
    
    
    def snapshot_init(sender, **kwargs):
        instance = kwargs.get('instance', None)
        # 由于这个信号在实例化后触发,就不分是否之前已经创建入库,还是新创建的对象,所以我们需要进行控制,只针对已经创建的对象
        # 区分他们只有pk了,没有创建的对象pk为None的。
        # 新创建的对象为什么不需要处理,既然需求提了,我们肯定已经对新创建这部分加上这个逻辑处理了,所以只对需求变更之前的数据进行处理
        if not instance.pk:
            return
        # 这里处理进行一些逻辑处理
        # instance就是实例化后的model对象,
        
    
    post_init.connect(snapshot_init, sender=Category)
    
    • 定义好信号,怎么触发呢,首先可以肯定的是不能任意位置导入这个信号执行,得在Django初始化所有app后才能开始监听我们的信号

    • apps.py这个文件就是为这个而设计的

    # apps.py
    from django.apps import AppConfig
    
    
    class AppConfig(AppConfig):
        name = 'app'
    
        def ready(self):
            # 从这里导入之前定义的信号模块
            from app import signal
    
    • 然后我们启动Django,等着信号触发吧

    。。。

    • 等了半天也没见信号触发,问题出在哪,Django从1.8之后注册app形式已经改为下面这种方式了

    • 当然我们这里只是示例,实际项目中,大家就不要取app这个名称了,否则上面那种AppConfig继承形式容易使人困惑

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app.apps.AppConfig',  # 新注册的app,通常这样也能用
    ]
    
    • 到这里就完了
  • 相关阅读:
    跟光磊学Python开发-面向对象入门
    插件调用下推操作
    K3Wise老单获取单据行数
    git 添加和删除 global 的 remote.origin.url
    CSV转Excel格式
    java 下载文件
    windows下安装redis并设置自启动
    linxu jdk安装
    Linux安装部署Redis
    CentOS上安装MySQL(使用国内源)
  • 原文地址:https://www.cnblogs.com/zengchunyun/p/9303571.html
Copyright © 2020-2023  润新知