You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过Django模型save方法设值时PostgreSQL触发器是否会执行?

问题解答

结论

只要Django对绑定了触发器的表发起INSERT/UPDATE操作,无论Django侧是否给created_at、updated_at赋值,PostgreSQL侧的触发器都会正常触发。

原因说明

触发器是数据库层面的执行规则,触发判断只和操作本身的属性有关:只要操作类型是INSERT/UPDATE、操作对象是绑定了触发器的表、符合行级触发的条件,不管操作来自Django ORM、原生SQL还是其他数据库客户端,都会触发执行。
你当前使用的是BEFORE INSERT OR UPDATE行级触发器,会在数据库正式写入行数据之前执行逻辑,所以会直接修改写入的值:哪怕Django已经给created_at/updated_at设了值,触发器也会用current_timestamp覆盖掉Django的赋值,最终数据库存储的是触发器生成的时间。

兼容方案

如果要避免两边逻辑冲突,可以选以下任意一种方案:

方案1:以数据库触发器的时间为准

将Django模型中的字段替换为普通的DateTimeField,关闭ORM自动赋值逻辑,完全交给触发器处理:

class TimeStampedModel(models.Model):
    created_at = models.DateTimeField(editable=False)
    updated_at = models.DateTimeField(editable=False)

    # 不需要自定义save方法处理赋值逻辑
    class Meta:
        abstract = True

方案2:以Django侧的赋值为准,触发器仅做兜底

修改触发器逻辑,仅在对应字段为空的时候才赋值,避免覆盖Django已经传入的时间:

CREATE OR REPLACE FUNCTION insert_update_function() RETURNS trigger AS $BODY$
BEGIN
  IF TG_OP = 'INSERT' THEN
    IF NEW.created_at IS NULL THEN
      NEW.created_at := current_timestamp;
    END IF;
    IF NEW.updated_at IS NULL THEN
      NEW.updated_at := current_timestamp;
    END IF;
  ELSE
    IF NEW.updated_at IS NULL THEN
      NEW.updated_at := current_timestamp;
    END IF;
  END IF;
  RETURN NEW;
END; $BODY$ LANGUAGE plpgsql VOLATILE;

该方案还有额外的兜底效果:当你使用update()、bulk_update()这类绕过save()方法的Django ORM操作时,Django不会自动更新updated_at,触发器会自动补上时间值。


内容的提问来源于stack exchange,提问作者A l w a y s S u n n y

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 05:06:03