Python中Firestore事务更新多文档失败及报错问题求助
问题分析与解决方案
错误原因
你遇到的AttributeError是因为**@firestore.async_transactional装饰器的使用方式错误**:
- 该装饰器要求被装饰的方法第一个参数必须是
transaction对象,装饰器会自动创建并传入这个参数。 - 你当前的方法第一个参数是
user_id(字符串类型),导致装饰器误将user_id当成了事务对象,从而抛出"str对象没有_read_only属性"的错误。 - 额外错误:类初始化时手动创建的
self.transaction属于冗余操作,且会干扰装饰器的事务管理逻辑。
修复后的代码
import firebase_admin import uuid from firebase_admin import credentials, firestore class FirestoreApi: def __init__(self): cred = credentials.ApplicationDefault() self.app = firebase_admin.initialize_app(cred) self.db = firestore.client() self.users = self.db.collection(u'users') self.projects = self.db.collection(u'projects') # 移除手动创建的transaction,由装饰器自动管理 @firestore.async_transactional async def create_project(self, transaction, user_id: str): # 使用装饰器注入的transaction参数获取文档 user_doc = self.users.document(user_id).get(transaction=transaction) if not user_doc.exists: raise Exception(f"User {user_id} not found in database.") project_id = str(uuid.uuid4()) new_project_ref = self.projects.document(project_id) project_data = { "id": project_id, "userIds": [user_id], } # 注意:如果用户已有projectIds,直接赋值会覆盖原有数据,建议用ArrayUnion追加 transaction.update(user_doc.reference, {"projectIds": firestore.ArrayUnion([project_id])}) transaction.set(new_project_ref, project_data) return project_data # 使用示例 api = FirestoreApi() project = await api.create_project("robert")
关键修复点说明
- 调整方法参数顺序:将
transaction作为create_project的第一个参数,由async_transactional装饰器自动注入。 - 移除手动事务实例:删除
__init__中的self.transaction,避免与装饰器管理的事务冲突。 - 正确使用事务对象:所有事务内的操作(
get/update/set)都使用装饰器传入的transaction参数。 - 优化数组更新逻辑:使用
firestore.ArrayUnion([project_id])替代直接赋值,避免覆盖用户已有的项目ID列表。
事务使用规则(Python异步版)
- 异步事务必须用
@firestore.async_transactional装饰,同步事务用@firestore.transactional。 - 装饰器会自动处理事务的开启、提交和回滚:如果方法内抛出异常,事务会自动回滚;执行成功则自动提交。
- 事务方法内的所有读写操作必须关联同一个事务对象(即装饰器注入的那个)。
内容的提问来源于stack exchange,提问作者Firefly
相关产品推荐
相关产品推荐

