Django中操作数据时异常导致数据行被删除问题求助
排查Django操作异常时数据行被删除的问题
这个问题我之前帮同事排查过几乎一模一样的情况——你换了PostgreSQL和SQLite都复现,说明根本和数据库类型无关,问题肯定出在你的Django代码逻辑里,大概率是异常处理分支的误操作或者事务/信号逻辑的疏漏,给你拆解几个常见原因和排查步骤:
最常见的坑:异常分支里的误删除代码
很多人在写try-except块时,会不小心在异常处理里加了delete()调用,比如复制粘贴代码时没改全:
def update_some_data(request, obj_id): try: obj = MyModel.objects.get(id=obj_id) # 这里的操作触发异常,比如字段验证失败、关联数据不存在 obj.some_field = invalid_value obj.save() except Exception as e: # 本来想打日志或者返回错误,结果不小心留了删除代码 obj.delete() return JsonResponse({"error": str(e)})
只要操作触发异常,就会执行obj.delete(),直接删掉数据库里的行。先把所有涉及该模型操作的try-except块扫一遍,90%的概率是这个问题。
信号处理器里的异常触发删除
如果你的模型注册了pre_save、post_save这类信号,有没有可能信号处理器里的逻辑在异常场景下触发了删除?比如:
from django.db.models.signals import pre_save from django.dispatch import receiver @receiver(pre_save, sender=MyModel) def my_model_pre_save(sender, instance, **kwargs): try: # 这里的操作抛出异常 validate_something(instance) except ValidationError: # 错误地删除了实例 instance.delete()
这种情况下,只要信号里的校验失败,就会删除当前要操作的实例,而且因为信号是隐式执行的,很容易被忽略。
事务逻辑的错误处理
Django 1.9默认对每个请求开启事务(数据库支持的话),如果你用了transaction.atomic(),捕获异常后如果对实例执行写操作(包括删除),就会绕过事务回滚直接修改数据库:
from django.db import transaction def process_data(request): try: with transaction.atomic(): obj = MyModel.objects.get(id=1) obj.some_field = invalid_value obj.save() # 这里抛出异常,事务会回滚 except Exception as e: # 事务回滚后,obj还是内存中的实例,此时调用delete()会直接删除数据库里的真实数据 obj.delete()
因为atomic()块里的异常会回滚所有操作,但你在块外获取的obj还是指向数据库里的真实行,此时执行删除就会真的删掉。
排查利器:开启SQL日志
如果上面的排查都没找到问题,直接开启Django的SQL日志,看异常发生时到底执行了哪些SQL语句,一眼就能看到DELETE语句的来源。在settings.py里添加:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'level': 'DEBUG', 'handlers': ['console'], }, }, }
运行代码触发异常后,控制台会打印所有执行的SQL,找到那条DELETE语句,就能反推是哪段代码触发的。
内容的提问来源于stack exchange,提问作者chitti
相关产品推荐
相关产品推荐

