我发现自己处于一种似乎没有优雅解决方案的情况。考虑以下(伪)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
我有
parent.rootDir
)所以基本上过程是
所以最后,问题是:
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)
我针对这种情况找到了不同的解决方案。对我来说,由于模式中自定义计算的属性,在
@post_dump
方法中进行数据替换太复杂了。我使用了 SQL Alchemy make_transient
函数。从会话中删除修改的对象。因此,对对象所做的任何更改都不会反映在数据库中。这样我就可以对对象进行任何修改并生成修改后的模式,而不需要重写整个 @pre_dump
函数。