Django 创建信号

Django Signals 是一种策略,允许解耦的应用程序在某些事件发生时得到通知。假设您想在每次更新给定模型实例时使缓存页面无效,但是您的代码库中有几个地方可以更新此模型。您可以使用信号来执行此操作,每次触发此特定模型的保存方法时,挂钩一些要执行的代码。

我应该什么时候使用它?

在我们继续之前,知道什么时候应该使用它:

当多段代码可能对相同的事件感兴趣时;
当您需要与解耦的应用程序交互时,例如:
一个 Django 核心模型;
由第三方应用程序定义的模型。

这个怎么运作?

如果您熟悉观察者设计模式,这就是 Django 实现它的方式。或者至少用于相同的目的。

信号机制中有两个关键元素:发送者和接收者。顾名思义, 发送者是负责发送信号的人,而接收者是接收该信号然后做某事的人。

接收器必须是接收信号的函数或实例方法。

发送者必须是 Python 对象,或者 None 才能接收来自任何发送者的事件。

发送者和接收者之间的连接是通过“信号调度器”完成的,它们是 Signal的实例,通过connect方法。

Django 核心还定义了一个ModelSignal,它是Signal的一个子类,它允许将发送者延迟指定为app_label.ModelName表单的字符串。但是,一般来说,您总是希望使用 Signal类来创建自定义信号。

因此,要接收信号,您需要注册一个接收器函数,该函数在使用Signal.connect()方法发送信号时被调用。

用法

让我们看看post_save内置信号。它的代码存在于django.db.models.signals模块中。此特定信号在模型完成其保存方法后立即触发。

from django.contrib.auth.models import User
from django.db.models.signals import post_save

def save_profile(sender, instance, **kwargs):
    instance.profile.save()

post_save.connect(save_profile, sender=User)

在上面的例子中,save_profile是我们的接收函数,User是发送者,post_save是 信号。您可以将其理解为:每次User实例完成其save方法的执行时, save_profile都会执行该函数。

如果您像这样抑制sender参数:post_save.connect(save_profile),该save_profile函数将在任何 Django 模型执行save方法后执行。

注册信号的另一种方法是使用@receiver装饰器:

def receiver(signal, **kwargs)

signal参数可以是Signal实例或Signal实例的列表/元组。

请参见下面的示例:

from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

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

如果您想将接收器功能注册到多个信号,您可以这样做:

@receiver([post_save, post_delete], sender=User)

代码应该放在哪里?

根据您注册应用程序信号的位置,可能会因为导入代码而发生一些副作用。因此,最好避免将其放在模型模块或应用程序根模块中。

Django 文档建议将信号放入您的应用程序配置文件中。请参阅下面我通常做的事情,考虑一个名为profiles的 Django 应用程序:

配置文件/signals.py:

from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

from cmdbox.profiles.models import 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()

配置文件/app.py:

from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _

class ProfilesConfig(AppConfig):
    name = 'cmdbox.profiles'
    verbose_name = _('profiles')

    def ready(self):
        import cmdbox.profiles.signals  # noqa

配置文件/init.py:

default_app_config = 'cmdbox.profiles.apps.ProfilesConfig'

在上面的示例中,只需在ready()方法中导入信号模块即可,因为我正在使用装饰器。如果您使用connect()方法连接接收器函数,请参考以下示例:@receiver()

配置文件/signals.py:

from cmdbox.profiles.models import Profile

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

def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

配置文件/app.py:

from django.apps import AppConfig
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _

from cmdbox.profiles.signals import create_user_profile, save_user_profile

class ProfilesConfig(AppConfig):
    name = 'cmdbox.profiles'
    verbose_name = _('profiles')

    def ready(self):
        post_save.connect(create_user_profile, sender=User)
        post_save.connect(save_user_profile, sender=User)

配置文件/init.py:

default_app_config = 'cmdbox.profiles.apps.ProfilesConfig'

注意:如果您已经在设置中引用了 AppConfig,则不需要 配置文件/init.pyINSTALLED_APPS位。

Django 内置信号

在这里您可以找到一些有用的内置信号的列表。它不完整,但这些是最常见的。

模型信号
django.db.models.signals。pre_init:

receiver_function(sender, *args, **kwargs)

django.db.models.signals。post_init:

receiver_function(sender, instance)

django.db.models.signals。预存:

receiver_function(sender, instance, raw, using, update_fields)

django.db.models.signals。post_save:

receiver_function(sender, instance, created, raw, using, update_fields)

django.db.models.signals。预删除:

receiver_function(sender, instance, using)

django.db.models.signals。post_delete:

receiver_function(sender, instance, using)

django.db.models.signals。m2m_changed:

receiver_function(sender, instance, action, reverse, model, pk_set, using)

请求/响应信号
django.core.signals。request_started:

receiver_function(sender, environ)

django.core.signals。请求完成:

receiver_function(sender, environ)

django.core.signals。got_request_exception:

receiver_function(sender, request)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值