You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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")

关键修复点说明

  1. 调整方法参数顺序:将transaction作为create_project的第一个参数,由async_transactional装饰器自动注入。
  2. 移除手动事务实例:删除__init__中的self.transaction,避免与装饰器管理的事务冲突。
  3. 正确使用事务对象:所有事务内的操作(get/update/set)都使用装饰器传入的transaction参数。
  4. 优化数组更新逻辑:使用firestore.ArrayUnion([project_id])替代直接赋值,避免覆盖用户已有的项目ID列表。

事务使用规则(Python异步版)

  • 异步事务必须用@firestore.async_transactional装饰,同步事务用@firestore.transactional。
  • 装饰器会自动处理事务的开启、提交和回滚:如果方法内抛出异常,事务会自动回滚;执行成功则自动提交。
  • 事务方法内的所有读写操作必须关联同一个事务对象(即装饰器注入的那个)。

内容的提问来源于stack exchange,提问作者Firefly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 05:12:35