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

问题描述 投票:0回答:2

我发现自己处于一种似乎没有优雅解决方案的情况。考虑以下(伪)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

我有

  • PUT 端点将创建新资源,然后返回该资源的转储。
  • 具有 filePath 属性的 ORM 对象。这必须存储为相对路径。
  • 棉花糖模式。它有一个 @pre_dump 方法,可以通过使用另一个属性来解析文件路径(
    parent.rootDir
    )

所以基本上过程是

  1. 创建新资源
  2. 创建要使用的资源的模式转储
  3. 承诺
  4. 返回架构转储

所以最后,问题是:

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
,然后在架构转储之后解析文件路径。但这对我来说真的很恶心。

我很想听听对此的任何想法,因为目前我的代码感觉很混乱,我不喜欢只是离开它并继续前进的想法。

python sqlalchemy marshmallow
2个回答
2
投票

通过使用

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

0
投票

我针对这种情况找到了不同的解决方案。对我来说,由于模式中自定义计算的属性,在

@post_dump
方法中进行数据替换太复杂了。我使用了 SQL Alchemy
make_transient
函数。从会话中删除修改的对象。因此,对对象所做的任何更改都不会反映在数据库中。这样我就可以对对象进行任何修改并生成修改后的模式,而不需要重写整个
@pre_dump
函数。

© www.soinside.com 2019 - 2024. All rights reserved.