SQLAlchemy:在插入或更新之前验证模型的最佳方法是什么

phi*_*ee2 6 python database orm sqlalchemy

我正在尝试在插入或更新之前验证 SQLAlchemy 模型,例如

class MyModel(db.Model):
    foo = db.Column(db.String(255))
    bar = db.Column(db.String(255))
Run Code Online (Sandbox Code Playgroud)

我尝试了几种方法,但似乎都不起作用。一种可能性是监听before_insertbefore_update事件,例如

@event.listens_for(MyModel, 'before_insert')
@event.listens_for(MyModel, 'before_update')
def validate_my_model(mapper, connection, model):
    if not is_valid(model):
        raise Exception("the model isn't valid")
Run Code Online (Sandbox Code Playgroud)

这工作正常,但在测试中我会收到此错误,除非我回滚会话。

This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback()
Run Code Online (Sandbox Code Playgroud)

我可以调用session.rollback()测试,但我这似乎不正确,因为测试只是发出 PUT/POST 请求,不应该真正了解会话或任何 SQLAlchemy 内部结构。

另一种选择是监听init事件,而不是before_insertand before_update,但这不处理更新情况。

我也尝试使用@validates,例如

@validates('foo', 'bar')
def validate(self, key, val):
    ...
Run Code Online (Sandbox Code Playgroud)

但是,验证依赖于这两个属性,而validate为每个属性单独调用该方法。这意味着,如果我尝试在模型上同时设置foobar,它会尝试验证一个属性已设置但另一个尚未设置的中间状态。

ali*_*m91 0

尝试flask-marshmallowmarshmallow_sqlalchemy,它基于marshmallow验证包。它允许您根据数据库模型进行验证。创建架构文件

import MyModel
import db
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema

class MyModelSchema(SQLAlchemyAutoSchema):
    class Meta:
        sqla_session = Session
        load_instance = True
        model = MyModel
Run Code Online (Sandbox Code Playgroud)

model在类内部添加Meta将有助于根据模型进行验证,并load_instance让我们将对象作为模型实例加载到 API 中

from schemas import MyModelSchema

model_schema = MyModelSchema()

# API post route
def post(self):
    model_json = request.get_json()
    model = model_schema.load(model_json)

    db.session(model)
    db.session.commit() 

    return {"message": "model created"}, 201

Run Code Online (Sandbox Code Playgroud)

最后向 Flask 应用程序内的用户 marshmallow 发送,如果发送的正文未经过验证,则返回验证错误消息,在应用程序根文件中添加

from flask_marshmallow import Marshmallow
from marshmallow import ValidationError

# marshmallow config
ma = Marshmallow(app)

# marshamallow global exception handler
@app.errorhandler(ValidationError)
def handle_marshmallow_validation(err):
    return jsonify(err.messages), 400
Run Code Online (Sandbox Code Playgroud)

希望这个对你有帮助。