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

iklwldmw  于 2023-08-02  发布在  Python
关注(0)|答案(3)|浏览(129)

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

class MyModel(db.Model):
    foo = db.Column(db.String(255))
    bar = db.Column(db.String(255))

字符串
我试过几种方法,但似乎都不管用。一种可能性是侦听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")


这可以正常工作,但在测试中,除非我回滚会话,否则我会得到此错误。

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


我可以在测试中调用session.rollback(),但这似乎是不正确的,因为测试只是发出PUT/POST请求,不应该真正知道任何关于会话或任何SQLAlchemy内部的信息。
另一种选择是侦听init事件,而不是before_insertbefore_update,但这不能处理更新情况。
我还尝试使用@validates,例如

@validates('foo', 'bar')
def validate(self, key, val):
    ...


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

polhcujo

polhcujo1#

试试flask-marshmallow和marshmallow_sqlalchemy,它基于marshmallow验证包。它允许您根据数据库模型进行验证。创建模式文件

import MyModel
import db
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema

class MyModelSchema(SQLAlchemyAutoSchema):
    class Meta:
        sqla_session = Session
        load_instance = True
        model = MyModel

字符串
Meta类中添加model将有助于基于模型进行验证,而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


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

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


我希望你觉得这有用。

hmmo2u0o

hmmo2u0o2#

使用提供的验证装饰器。参见:sqlalchemy.orm.validates
示例如下:

from sqlalchemy.orm import validates

class MyModel(...):
    
    # ...

    status = db.Column(db.String)

    # ...

    @validates("status")
    def validate_status(self, k, status):
        if status.upper() not in ["PENDING", "APPROVED", "DENIED"]:
            raise ValueError("OOPS, invalid status.")
        return status

字符串

t5zmwmid

t5zmwmid3#

你可以使用SQLModel,它允许你声明一个继承自SQLModel的类。

class Hero(SQLModel, talbe=):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None

字符串
这是pydantic字段到sqlalchemy列的类Map。
示例化错误的对象将引发ValidationError
请参考Pydantic documentation以检查验证/确认器是如何工作的

相关问题