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的方法根本不会触发。
解决步骤
- 调整继承顺序:把
LoggingMixin放在继承列表最前面,让MRO优先查找Mixin的方法:
class ExistingCalculationsForUrl(LoggingMixin, Basemodel): # 原有字段及Meta类保持不变
- 修正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
相关产品推荐
相关产品推荐

