Django异常块内执行Model.objects.create数据未入库问题
问题现象
开发Django应用时出现异常场景:在抛出异常前、或except异常捕获块内执行Model.objects.create(**obj)时,代码运行无报错,但数据库中查询不到对应创建的对象,执行Model.objects.all()也无法返回该记录。
单步测试代码:
Model.objects.create(**obj)
完整业务代码如下:
def has_permission(self, request, view): try: serializer = VerifyOTPRequestSerializer(data=request.data) serializer.is_valid(raise_exception=True) otp = request.data.pop("otp") flow = request.data.pop("flow") primary_phone = request.data.get("contact_detail", {}).get( "primary_phone", "" ) if OTPFailedAttempts.objects.filter(phone=primary_phone).count() > 0: raise Exception("otpAttemptError") return helpers.OTPHelper.verify_otp(primary_phone, otp, flow) except Exception as permission_error: OTPFailedAttempts.objects.create(**{"phone": primary_phone, 'email': email}) return False
补充数据库配置:
ATOMIC_REQUESTS = True
核心疑问:该问题是Django本身限制了异常场景附近的模型对象创建操作,还是代码写法存在错误?
问题成因
该问题和Django的事务机制、代码逻辑缺陷都有关系,不是Django刻意限制异常场景的写入操作:
- 配置
ATOMIC_REQUESTS = True后,Django会将每个请求的整个视图处理流程(包括DRF的认证、权限、限流校验逻辑)包裹在一个全局数据库事务中,只有请求链路全程无未捕获异常、正常返回响应时才会提交全量事务;只要最终有异常抛出触发事务回滚,事务内的所有数据库写入操作都会被撤销。 - 代码中
except块执行完创建操作后直接return False,DRF框架收到has_permission返回的False结果后,会自动抛出PermissionDenied异常生成403响应,该异常会触发全局请求事务回滚,except块中写入的OTPFailedAttempts记录属于同一个事务,会被同步回滚,因此数据库中查询不到。 - 代码存在隐藏逻辑bug:
except块中使用的email变量、部分异常分支下的primary_phone变量没有提前赋值。如果触发异常的路径未走到变量赋值的代码行,create语句会直接抛出NameError,又被代码中全量捕获Exception的逻辑吞掉,既不会暴露报错,也不会完成实际写入。
修复方案
- 异常场景下必须持久化的写入操作,单独开启独立事务执行,和全局请求事务做隔离,避免被外层回滚逻辑影响:
from django.db import transaction # 替换except块中的原有创建逻辑 with transaction.atomic(): # 提前校验所有传入字段已正确赋值 OTPFailedAttempts.objects.create(phone=primary_phone, email=email)
- 修复变量未定义问题:将
primary_phone、email等字段的取值逻辑移到try块最前端,或在取值时增加默认值判断,确保所有进入except块的路径下,创建模型需要的字段都已完成赋值。 - 不要裸抛、全量捕获
Exception,针对性捕获业务类异常即可,避免吞掉序列化校验失败、变量未定义、数据库连接错误等非预期异常,干扰问题排查。
内容的提问来源于stack exchange,提问作者Tahreem Iqbal
相关产品推荐
相关产品推荐

