使用Django transaction.atomic时更新回滚但记录创建成功问题求助
问题分析与解决方案
你的问题核心在于事务交互和潜在的信号干扰,以下是具体分析和修复步骤:
1. 模型方法中get_queryset定义错误
你把get_queryset定义为Profile的实例方法,这不符合Django的设计规范——get_queryset是模型管理器的方法,而非实例方法。虽然当前代码能运行,但可能引发不可预期的查询行为,建议修正为自定义管理器:
from django.db import models, transaction class ProfileManager(models.Manager): def get_queryset(self): return super().get_queryset() class Profile(models.Model): age = models.IntegerField() user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') objects = ProfileManager() # 绑定自定义管理器 @transaction.atomic def update_age(self, age: int) -> None: # 直接通过管理器查询并锁定目标行 obj = Profile.objects.select_for_update().get(id=self.id) obj.age = age obj.save()
2. 事务范围不匹配导致的回滚
你在模型方法中单独使用@transaction.atomic,而视图中的UpdateHistory创建操作在独立事务中。这种分离可能导致:如果UpdateHistory创建触发了某些信号(如post_save),该信号若意外操作了Profile实例(比如使用了缓存的旧实例并保存),会覆盖update_age的更新,看起来像是“回滚”。
修复方案:将所有操作纳入同一事务
把视图和模型方法的事务统一,确保更新Profile和创建UpdateHistory要么同时成功,要么同时失败,避免中间状态:
视图代码修改:
from django.db import transaction class UserProfileView(APIView): @transaction.atomic def put(self, request): profile = request.user.profile profile.update_age(request.data["age"]) UpdateHistory.objects.create(user=request.user, updated_field="age")
模型方法调整(可选,移除内层事务,由视图统一管控):
class Profile(models.Model): # ... 其他字段和管理器定义 ... def update_age(self, age: int) -> None: obj = Profile.objects.select_for_update().get(id=self.id) obj.age = age obj.save()
3. 排查信号干扰
重点检查与UpdateHistory、User、Profile相关的信号(如post_save),确认是否有代码在创建UpdateHistory时,意外保存了缓存的旧Profile实例。例如:
# 错误示例:使用缓存的旧实例导致覆盖更新 @receiver(post_save, sender=UpdateHistory) def on_history_created(sender, instance, **kwargs): # 这里的instance.user.profile是缓存的旧实例,age还是更新前的值 instance.user.profile.save()
修复信号代码:
如果存在此类信号,需重新从数据库读取最新的Profile实例:
@receiver(post_save, sender=UpdateHistory) def on_history_created(sender, instance, **kwargs): # 读取最新的Profile实例 profile = Profile.objects.get(id=instance.user.profile.id) # 执行必要操作后保存 profile.save()
4. 验证数据库引擎
确保你的数据库使用支持事务的引擎(如MySQL的InnoDB、PostgreSQL),MyISAM等不支持事务的引擎会导致select_for_update和atomic失效。
内容的提问来源于stack exchange,提问作者Temi
相关产品推荐
相关产品推荐

