处理 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
我有
- 将创建新资源的 PUT 端点,然后 return 该资源的转储。
- 具有文件路径 属性 的 ORM 对象。这必须存储为相对路径。
- 棉花糖模式。它有一个 @pre_dump 方法,通过使用另一个 属性 (
parent.rootDir
) 来解析文件路径
所以基本上流程是
- 创建新资源
- 创建该资源的模式转储以供使用
- 提交
- 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)
我发现自己处于一种似乎没有优雅解决方案的情况。考虑以下(伪)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 端点,然后 return 该资源的转储。
- 具有文件路径 属性 的 ORM 对象。这必须存储为相对路径。
- 棉花糖模式。它有一个 @pre_dump 方法,通过使用另一个 属性 (
parent.rootDir
) 来解析文件路径
所以基本上流程是
- 创建新资源
- 创建该资源的模式转储以供使用
- 提交
- 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)