Django中字段变化触发的操作

54 投票
8 回答
56716 浏览
提问于 2025-04-15 13:14

我想知道,当我的模型中的某个字段发生变化时,如何触发一些操作。在这个例子中,我有一个模型:

class Game(models.Model):
    STATE_CHOICES = (
        ('S', 'Setup'),
        ('A', 'Active'),
        ('P', 'Paused'),
        ('F', 'Finished')
        )
    name = models.CharField(max_length=100)
    owner = models.ForeignKey(User)
    created = models.DateTimeField(auto_now_add=True)
    started = models.DateTimeField(null=True)
    state = models.CharField(max_length=1, choices=STATE_CHOICES, default='S')

我希望在状态从“设置”变为“活动”时,创建单位,并且将“开始”字段填入当前的日期和时间(还有其他一些操作)。

我觉得可能需要一个模型实例的方法,但文档里似乎没有太多关于如何以这种方式使用它们的说明。

更新:我在我的游戏类中添加了以下内容:

    def __init__(self, *args, **kwargs):
        super(Game, self).__init__(*args, **kwargs)
        self.old_state = self.state

    def save(self, force_insert=False, force_update=False):
        if self.old_state == 'S' and self.state == 'A':
            self.started = datetime.datetime.now()
        super(Game, self).save(force_insert, force_update)
        self.old_state = self.state

8 个回答

20

Django 有一个很棒的功能叫做 信号,简单来说就是在特定的时刻触发的一些动作:

  • 在模型的保存方法被调用之前或之后
  • 在模型的删除方法被调用之前或之后
  • 在发出 HTTP 请求之前或之后

想了解更多详细信息,可以去看看文档,但其实你只需要创建一个接收函数,并把它注册为信号。这通常是在 models.py 文件里完成的。

from django.core.signals import request_finished

def my_callback(sender, **kwargs):
    print "Request finished!"

request_finished.connect(my_callback)

简单吧?

46

这个问题已经有人回答过了,不过我这里给你举个例子,讲讲怎么使用信号、post_init和post_save。

from django.db.models.signals import post_save, post_init

class MyModel(models.Model):
    state = models.IntegerField()
    previous_state = None

    @staticmethod
    def post_save(sender, instance, created, **kwargs):
        if instance.previous_state != instance.state or created:
            do_something_with_state_change()

    @staticmethod
    def remember_state(sender, instance, **kwargs):
        instance.previous_state = instance.state

post_save.connect(MyModel.post_save, sender=MyModel)
post_init.connect(MyModel.remember_state, sender=MyModel)
23

基本上,你需要重写一下 save 方法,检查一下 state 字段有没有被修改,如果需要的话就设置 started,然后让模型的基类继续把数据保存到数据库里。

比较棘手的部分是要弄清楚这个字段有没有被改动。可以看看这个问题中的 mixins 和其他解决方案,帮助你理解:

撰写回答