处理 Marshmallow 改变 SQLAlchemy 对象的优雅方式

Elegant Way to Deal with Marshmallow Altering a SQLAlchemy Object

我发现自己处于一种似乎没有优雅解决方案的情况。考虑以下(伪)REST API 代码


bp = Blueprint('Something', __name__, url_prefix='/api')

class SomeOutputSchema(ma.SQLAlchemyAutoSchema)
    class Meta:
        model = MyModel

    @pre_dump(pass_many=False)
    def resolveFilePath(self, ormObject, many):
        # ormObject has a parent via a relationship
        ormObject.filePath = os.path.join(ormObject.parent.rootDir, ormObject.filePath)


@bp.route("/someRoute")
class SomeClass(MethodView):

    def put(self):
        ormObject = MyModel(filePath = "/some/relative/path")
        db.session.add(ormObject)
        db.session.flush()

        outputDump = SomeOutputSchema().dump(ormObject)

        # Lots of other code that uses outputDump...

        # Only commit here in case 
        # anything goes wrong above

        db.session.commit()
        
        return jsonify({"data": outputDump}), 201

我有

所以基本上流程是

  1. 创建新资源
  2. 创建该资源的模式转储以供使用
  3. 提交
  4. Return 模式转储

所以终于,问题是:outputDump@pre_dump实际上改变了ormObject,所以现在完全解决了调用 db.session.commit() 时的路径。我的第一直觉是创建 ormObject 的深层副本,但失败了

"Parent instance <MyModel at 0x7f31cdd44240> is not bound to a Session; lazy load operation of attribute 'parent' cannot proceed (Background on this error at: http://sqlalche.me/e/14/bhk3)"

并不是说这是一件很难解决的事情,但以我目前的知识优雅似乎很难解决。我需要数据库的相对路径,否则就解决了。 我目前的解决方案是告诉 SomeOutputSchema 在这种情况下跳过 @pre_dump,然后采用 outputDump,然后在模式转储之后解析文件路径。但这对我来说真的很恶心。

我很想听听关于这个的任何想法,因为目前我的代码感觉很乱,我不喜欢就这样离开它继续推进。

解决方法是使用 @post_dump 并使用 pass_original=True 获取对原始对象的访问权限

class SomeOutputSchema(ma.SQLAlchemyAutoSchema)
    class Meta:
        model = MyModel

    @post_dump(pass_original=True)
    def resolveFilePath(self, data, ormObject, many):
        data['filePath'] = os.path.join(ormObject.parent.rootDir, ormObject.filePath)