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

Django模型LoggingMixin失效:save/delete未触发日志记录

Django LoggingMixin 未生效:save()方法未被调用

我想让所有Django模型都继承LoggingMixin类,实现保存、更新、删除操作及错误的日志记录,但现在遇到问题:实际调用的是标准save()方法而非Mixin中定义的save(),Mixin里的print语句完全没执行,报错时回溯只指向视图里的object.save(),不会显示Mixin里抛出的错误。其他日志功能正常,对象能正常保存删除,但日志完全没记录,求解决办法。


相关代码实现

LoggingMixin 代码

import logging
logger = logging.getLogger(__name__)

## 本文件定义一个Mixin,用于记录所有保存、更新、删除操作及错误

class LoggingMixin:
    
    def save(self, *args, **kwargs):
        try:
            print("---------------------------------------------------------------1")
            if hasattr(self.pk):
                print("---------------------------------------------------------------2")
                if self.pk is None:
                    # 对象为新创建
                    print("---------------------------------------------------------------3")
                    super(LoggingMixin, self).save(*args, **kwargs)
                    logger.info(f"{self._meta.db_table} object saved: " + str(str(self).split('\n')[1]))
                else:
                    # 对象正在更新
                    print("---------------------------------------------------------------4")
                    super(LoggingMixin, self).save(*args, **kwargs)
                    logger.info(f"{self._meta.db_table} object updated: " + str(str(self).split('\n')[1]))
            else:
                # 对象正在更新
                print("---------------------------------------------------------------5")
                super(LoggingMixin, self).save(*args, **kwargs)
                logger.info(f"{self._meta.db_table} object updated: " + str(str(self).split('\n')[1]))
        # 保存时出错
        except Exception as e:
            print("-------------------------------------------------------------6")
            logger.error(f"Error saving {self._meta.db_table} object: " + str(str(self).split('\n')[1]) + f"Error: {e}")
            raise e

    def delete(self, *args, **kwargs):
        # 删除日志
        try:
            super(LoggingMixin, self).delete(*args, **kwargs)
            logger.info(f"{self._meta.db_table} object deleted. ID: {str(self.pk)}")
        # 删除时出错
        except Exception as e:
            logger.error(f"Error deleting {self._meta.db_table} object: " + str(str(self).split('\n')[1]) + f"Error: {e}")
            raise e

继承Mixin的模型示例

class ExistingCalculationsForUrl(Basemodel, LoggingMixin):
    url = models.CharField(max_length=512)
    content_type = models.ForeignKey(ContentType, on_delete=models.PROTECT, default=None)
    object_id = models.UUIDField(default=uuid.uuid4, editable=False)
    content_object = GenericForeignKey('content_type', 'object_id')
    week = models.ForeignKey('Weeks', on_delete=models.CASCADE, related_name='%(class)s_related_week')
    existing_calculation = models.JSONField()

    class Meta:
        managed = True
        db_table = 'existing_calculations_for_url'
        constraints = [models.UniqueConstraint(fields=['url', 'object_id', 'week'], name='unique_existing_calculation_for_url')]

问题原因及解决办法

核心问题:Mixin继承顺序错误

Django模型的方法解析顺序(MRO)是从左到右查找的。你的模型ExistingCalculationsForUrl先继承Basemodel再继承LoggingMixin,如果Basemodel本身继承了models.Model(或自带save()方法),那么Basemodel的save()会被优先调用,LoggingMixin的方法根本不会触发。

解决步骤

  1. 调整继承顺序:把LoggingMixin放在继承列表最前面,让MRO优先查找Mixin的方法:
class ExistingCalculationsForUrl(LoggingMixin, Basemodel):
    # 原有字段及Meta类保持不变
  1. 修正super调用:不要硬编码父类为LoggingMixin,改用无参数的super()让Python自动根据MRO找下一个父类方法:
# LoggingMixin的save方法中,替换所有super调用
super().save(*args, **kwargs)

# delete方法同理替换
super().delete(*args, **kwargs)

额外优化建议

  • 移除调试用的print语句,正式环境用日志记录即可
  • 简化对象字符串处理:避免split('\n')[1]可能引发的索引错误,建议自定义模型的__str__方法,直接返回清晰的标识
  • 可选方案:用Django信号(pre_save/post_save/pre_delete/post_delete)实现日志,无需修改模型继承,扩展性更强

内容的提问来源于stack exchange,提问作者BerndKarlsb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:12:11