【问题标题】:Django signals for models value change condition?模型值变化条件的 Django 信号?
【发布时间】:2016-12-26 08:44:38
【问题描述】:

我的 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

在这种情况下,我在我的 signals.py 中做了一个非常简单的逻辑来检查新字段(新音乐)是否刚刚添加到专辑中。

Album(musician="someone", music=Music.objects.get(title="something")) #pk=1
Album.save()

像这样:

@receiver(post_save, sender=Album)
def add_new_album(sender, instance, **kwargs):   
    if kwargs.get('created'):
       print "new album recently created"

在其他情况下,我想发出仅在将现有字段编辑为新字段时才响应的信号:

edit_album = Album.objects.get(pk=1)
edit_album.music = Music.objects.get(title="something_else")
edit_album.save()

每次我编辑现有字段时都会触发 post_save 接收器 make add_new_album() 函数的使用。所以我的问题是,在仅响应编辑字段条件的 signals.py 中应该实现的逻辑是什么?

【问题讨论】:

    标签: python django signals


    【解决方案1】:

    我知道这是一个老问题,但我最近遇到了这个特殊问题,我想分享我的初步解决方案,以防它帮助其他人甚至是原始海报。或者更好的是,激发讨论以提出更好的解决方案。

    我不想使用任何第三方库(尤其是在 DB 上进行迁移的库)并且想使用 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")
    

    2) 创建我想在特定字段更改时发送的自定义信号

    album_music_changed = Signal(providing_args=[])
    

    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)
    

    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)
    

    在我的情况下,我需要在实例的 post_save 之后运行该函数,所以这是我能想到的最好的事情,如果有人有更好的解决方案,如果你能分享它会很棒。

    当然,如果您不需要触发函数来运行 post_save 并且您很乐意运行它 pre_save 您可以在第一个“if”块中调用 .send() 而不必担心 post_save 接收器

    希望对你有帮助

    【讨论】:

      【解决方案2】:

      所以我只想在某些字段发生更改时触发信号,对吗? 你可以使用一个名为Django Field history的包

      类似这样的:

      @receiver(post_save, sender=<sender>, dispatch_uid=<string>)
      def method(sender, instance, **kwargs):
          last_field_change = FieldHistory.objects.filter(field_name=<your_field_which_you_want_to_check_for_change>,
                                                object_id=instance.id).last()
          if last_field_change:
               #do your thing
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-27
        • 2023-04-03
        • 1970-01-01
        • 2022-01-17
        • 2011-03-31
        • 2011-10-19
        相关资源
        最近更新 更多