Flask Python模型验证

2024-04-25 09:00:33 发布

您现在位置:Python中文网/ 问答频道 /正文

来自php背景,我正在通过Flask学习python。我已经为客户端使用了WTForms,这很好地处理了验证。

不过,我想使用flask的一个原因是一个公共API,在这种情况下,我希望所有的验证都在我的模型上运行。我以为SQLAlchemy会包含验证功能,但事实并非如此。

我遇到过Colander,看起来不错,但我有点惊讶,没有比这更普遍的验证库。更让人惊讶的是,SQLAlchemy并不是以本机的方式来实现这一点的。

这里有什么选择?也许我漏掉了一些东西,但是如何轻松地验证模型数据呢?


Tags: 模型功能api客户端flasksqlalchemy情况原因
3条回答

你考虑过在模型层进行验证吗

这将允许您拥有完全干燥的解决方案,因为无论更新源是用户发送的数据,还是作为间接更新一部分更新模型的应用程序组件,都将自动触发验证。简而言之,您还可以在前端使用WTForms重用此解决方案,并且只有一个地方可以对API和前端进行验证。

有关在模型中进行验证的更多优点,请参见this answer


…使用SQLAlchemy提供的工具?

一。The ^{} decorator用于简单验证:

使用这个decorator非常简单:只需将它应用于要验证的字段:

from sqlalchemy.orm import validates

class EmailAddress(Base):
    __tablename__ = 'address'

    id = Column(Integer, primary_key=True)
    email = Column(String)

    @validates('email')
    def validate_email(self, key, address):
        assert '@' in address
        return address

2。ORM Events对于复杂的业务规则:

当模型实例的某个属性发生更改时,可以使用属性事件直接执行复杂验证。使用属性事件的优点是可以保证会话中的数据(内存中的对象)处于已验证状态。

下面是docs中的一个示例(一个简单的,但您应该考虑这里的复杂规则):

def validate_phone(target, value, oldvalue, initiator):
    "Strip non-numeric characters from a phone number"

    return re.sub(r'(?![0-9])', '', value)

# setup listener on UserContact.phone attribute, instructing
# it to use the return value
listen(UserContact.phone, 'set', validate_phone, retval=True)

您还可以使用映射器事件(如^{})来推迟对session.add()调用的验证,甚至使用Session Events来拦截提交。。。但是您在会话中失去了数据的完整性保证。。。

只要输入的数据可以以类似于多Dict的格式读取,就没有理由仍然不能使用WTForms进行验证(尽管,这比使用Colander要尴尬一些)。

因此,对于一个产生和使用JSON的假设API,您可以这样做:

class MyDataStructure(Form):
    widget = TextField("Widget", validators=[Required()])
    quantity = IntegerField("Quantity", validators=[Required()])

@app.route("/api/v1/widgets", methods=["POST"])
def widgets():
    try:
        new_widget_info = json.loads(request.form.data)
    except KeyError:
        return jsonify(error="Must provide widget JSON in data param")
    except ValueError:
        return jsonify(error="Invalid JSON Provided")

    data = MyDataStructure(**new_widget_info)
    if not data.validate():
        return jsonify(error="Missing or invalid data",
                           error_details=data.errors)
    else:
        # Create a new widget

我正在为此编写一个名为Flask-Inputs的库。

与Colander类似,您定义模式并根据它们验证输入。就像@Sean Vieira的建议一样,它依赖WTForms进行验证。

在内部,它将所有的request输入数据转换为multidict。与WTForms一样,您可以定义自定义验证器(一个内置的自定义验证器用于request.json数据,它使用jsonschema进行验证)。

因为听起来像是在对发布到公共API的数据运行验证,下面是API密钥和发布的JSON验证的示例。

from flask_inputs import Inputs
from flask_inputs.validators import JsonSchema

schema = {
    'type': 'object',
    'properties': {
        'name': {'type': 'string'}
    }
}

class ApiInputs(Inputs):
    headers = {
        'Authorization': [DataRequired(), valid_api_key]
    }
    json = [JsonSchema(schema=schema)]

然后在你的路线上:

@app.route('/api/<version>/endpoint')
def endpoint():
    inputs = ApiInputs(request)

    if not inputs.validate():
        return jsonify(success=False, errors=inputs.errors)

我发现(在生产中使用它)最大的好处是在一个地方显示所有错误。覆盖所有传入数据的良好验证器可防止生产中出现许多意外/未定义的行为。

相关问题 更多 >