使用django-pgtrigger遇Meta类triggers未定义错误,求日志实现方案
问题1:NameError: name 'triggers' is not defined
这个错误是因为Django的Model.Meta类默认不识别triggers属性,改用@pgtrigger.register装饰器是更稳妥的触发器注册方式,修改后的代码如下:
from django.db import models import pgtrigger @pgtrigger.register( pgtrigger.Protect( name='protect_deletes', operation=pgtrigger.Delete, condition=pgtrigger.Q(old__is_active=True) ) ) class ProtectedModel(models.Model): """Active object cannot be deleted!""" is_active = models.BooleanField(default=True)
如果坚持使用Meta类的方式,需要确保:
pgtrigger已添加到项目的INSTALLED_APPS配置中- 执行过
python manage.py makemigrations和python manage.py migrate命令,将触发器同步到数据库 - 代码缩进正确,
triggers确实定义在Meta类内部
问题2:基于触发器的数据库日志方案
方案1:使用django-pghistory(与django-pgtrigger配套)
这是官方推荐的日志工具,能自动通过触发器记录模型的所有变更,上手非常简单:
- 安装依赖:
pip install django-pghistory - 在
INSTALLED_APPS中添加pghistory - 用
@pghistory.track()装饰需要记录日志的模型:
import pghistory from django.db import models @pghistory.track() class YourModel(models.Model): name = models.CharField(max_length=100) # 其他业务字段...
执行migrations后,会自动生成对应的历史表,所有增删改操作都会被记录,包括变更前后的数据、操作时间、执行用户等信息。
方案2:自定义触发器日志
如果需要更灵活的日志内容控制,可以用django-pgtrigger手动实现:
- 先创建日志模型:
from django.db import models from django.utils import timezone class ModelChangeLog(models.Model): model_name = models.CharField(max_length=100) object_id = models.CharField(max_length=255) change_type = models.CharField(max_length=10, choices=[('INSERT', '新增'), ('UPDATE', '更新'), ('DELETE', '删除')]) old_data = models.JSONField(null=True) new_data = models.JSONField(null=True) changed_at = models.DateTimeField(default=timezone.now) changed_by = models.CharField(max_length=100, null=True) # 可结合request记录操作用户
- 用
pgtrigger.Trigger定义触发器逻辑,通过SQL函数插入日志:
import pgtrigger @pgtrigger.register( pgtrigger.Trigger( name='log_yourmodel_changes', operation=pgtrigger.Insert | pgtrigger.Update | pgtrigger.Delete, func=pgtrigger.Func( """ INSERT INTO yourapp_modelchangelog ( model_name, object_id, change_type, old_data, new_data, changed_at ) VALUES ( 'YourModel', CASE WHEN TG_OP = 'DELETE' THEN OLD.id ELSE NEW.id END, TG_OP, CASE WHEN TG_OP != 'INSERT' THEN row_to_json(OLD) ELSE NULL END, CASE WHEN TG_OP != 'DELETE' THEN row_to_json(NEW) ELSE NULL END, NOW() ); """ ), when=pgtrigger.After ) ) class YourModel(models.Model): name = models.CharField(max_length=100) # 其他业务字段...
这种方式可以完全自定义日志内容,但需要编写SQL函数,适合有特定需求的场景。
内容的提问来源于stack exchange,提问作者Nick S
相关产品推荐
相关产品推荐

