使用Python Tortoise ORM更新关联UserInfo模型时出现操作错误
通过Tortoise ORM关联更新PostgreSQL数据时的错误排查
问题场景
我用Tortoise ORM操作PostgreSQL,定义了一对OneToOne关联的模型:
class User(Model): class Meta: table = "users" id = fields.UUIDField(primary_key=True) internal_id = fields.IntField(unique=True) info: fields.ReverseRelation["UserInfo"] class UserInfo(Model): class Meta: table = "user_infos" id = fields.UUIDField(primary_key=True) rank = fields.IntField() user = fields.OneToOneField("app.User", related_name="info")
尝试通过用户的internal_id更新UserInfo时触发错误:
await UserInfo.filter(user__internal_id=SOME_ID).update(rank=5)
错误信息:
tortoise.exceptions.OperationalError: invalid reference to FROM-clause entry for table "user_infos" HINT: There is an entry for table "user_infos", but it cannot be referenced from this part of the query.
生成的错误SQL:
UPDATE "user_infos" SET "rank"=$1 FROM "user_infos" "user_infos_" LEFT OUTER JOIN "users" "user_infos__user" ON "user_infos__user"."id"="user_infos"."user_id" WHERE "user_infos__user"."internal_id"=893706004;
单独执行过滤查询能正常返回UserInfo对象:
await UserInfo.filter(user__internal_id=internal_id)
错误原因
Tortoise ORM生成的更新SQL存在逻辑错误:在FROM子句里重复引入了user_infos表(别名user_infos_),同时主更新表也是user_infos。PostgreSQL在这种情况下无法正确解析主表和FROM子句中同表的引用关系,因此抛出错误。
而查询操作时,Tortoise生成的是标准的JOIN查询,不会重复引入目标表,所以能正常执行。
解决方案
方案1:通过反向关联从User模型发起更新
利用OneToOne字段定义的related_name="info",直接从User模型出发关联更新UserInfo:
await User.filter(internal_id=SOME_ID).update(info__rank=5)
方案2:先获取目标用户ID再更新
先查询到目标用户的ID,再用该ID过滤UserInfo进行更新:
# 方式1:先查询用户对象 target_user = await User.get(internal_id=SOME_ID) await UserInfo.filter(user_id=target_user.id).update(rank=5) # 方式2:用子查询直接过滤 await UserInfo.filter(user_id=User.filter(internal_id=SOME_ID).values("id")).update(rank=5)
内容的提问来源于stack exchange,提问作者picKit
相关产品推荐
相关产品推荐

