Fai*_*rbw 1 python django signals
我的 models.py 中有一个非常简单的模型,如下所示:
class Music(models.Model):
title= models.CharField(
max_length=100
)
description = models.TextField(
null=True,
blank=True
)
def __unicode__(self):
return self.name
class Album(models.Model):
musician= models.CharField(
related_name='musician',
max_length=100
)
music = models.ForeignKey(
Music,
related_name='music'
)
def __unicode__(self):
return self.user.username
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我在 signal.py 中做了一个非常简单的逻辑来检查新字段(新音乐)是否刚刚添加到专辑中。
Album(musician="someone", music=Music.objects.get(title="something")) #pk=1
Album.save()
Run Code Online (Sandbox Code Playgroud)
像这样:
@receiver(post_save, sender=Album)
def add_new_album(sender, instance, **kwargs):
if kwargs.get('created'):
print "new album recently created"
Run Code Online (Sandbox Code Playgroud)
在其他情况下,我想发出一个只有在将现有字段编辑为新字段时才会响应的信号:
edit_album = Album.objects.get(pk=1)
edit_album.music = Music.objects.get(title="something_else")
edit_album.save()
Run Code Online (Sandbox Code Playgroud)
每次我编辑现有字段时,都会触发 post_save 接收器 make add_new_album() 函数的使用。所以我的问题是,在 signal.py 中应该实现的仅响应编辑字段条件的逻辑是什么?
我知道这是一个老问题,但我最近遇到了这个特殊问题,我想分享我的初步解决方案,以防它对其他人甚至原始海报有所帮助。或者更好的是,激发讨论以提出更好的解决方案。
我不想使用任何第三方库(尤其是在数据库上进行迁移的库),而是想使用 Django 提供的内置信号。
我的解决方案是:
1)创建我想要在特定字段发生更改时触发的函数(在提问者的情况下是专辑实例上的音乐字段)
def do_this_when_album_music_changed(sender, **kwargs):
// do something
print("I'm only going to be called if the field has changed")
Run Code Online (Sandbox Code Playgroud)
2)创建我想要在特定字段更改时发送的自定义信号
album_music_changed = Signal(providing_args=[])
Run Code Online (Sandbox Code Playgroud)
3) 创建一个 pre_save 信号接收器,它将检查字段是否已更改并将自定义信号“连接”到接收器,否则“断开连接”
@receiver(signal=signal=models.signals.pre_save, sender=Album)
def album_pre_save(sender, instance, **kwargs):
old_album = sender.objects.get(pk=instance.pk)
if not old_album.music == instance.music:
album_music_changed.connect(do_this_when_album_music_changed, sender=Album)
else:
album_music_changed.disconnect(do_this_when_album_music_changed, sender=Album)
Run Code Online (Sandbox Code Playgroud)
4)最后添加一个 post_save 信号,该信号将实际发送触发器来调用自定义信号,从而发送您想要运行的函数
@receiver(signal=signal=models.signals.post_save, sender=Album)
def album_post_save(sender, instance, **kwargs):
album_music_changed.send(sender=sender)
Run Code Online (Sandbox Code Playgroud)
就我而言,我需要在实例的 post_save 之后运行该函数,所以这是我能想到的最好的办法,如果有人有更好的解决方案,如果您可以分享它,那就太棒了。
当然,如果您不需要触发函数来运行 post_save 并且您很乐意在 pre_save 之前运行它,您可以只在第一个“if”块内调用 .send() ,而不必担心 post_save 接收器
希望这可以帮助