1:第十章 待办事项程序,p466中介绍了使用webargs作为大型程序的字段验证
2:在对一个键使用自定义验证规则时如何引入其它键值作为验证条件
3:验证场景在对用户信息进行修改操作时,需要根据用户的id来修改用户名称等信息,其中用户名称是需要做全局唯一的验证,但在验证的时在做全局唯一验证的时候要刨除自己本身,也就是查询语句User.query.filter_by(username=‘test’).filter(User.id!=1).first()
具体伪代码如下
from webargs import fields, validate, ValidationError
def must_not_exist_in_db(val):
if User.query.filter_by(username=val).first():
raise ValidationError("User does not exist")
user_update = {
"id": fields.Int(required=True),
"username": fields.Str(required=True, validate=must_not_exist_in_db),
"password": fields.Str(validate=lambda p: len(p) >= 6),
}
@app.route("/update", methods=["POST"])
@use_args(user_update )
def update(args):
.......
return True
例如在上述代码中如果需要对username做自定义的验证时(must_not_exist_in_db),如何引入其他的键值,或者有什么办法达到以下目的
def must_not_exist_in_db(val):
if User.query.filter_by(username=val).filter(User.id!=id).first():
raise ValidationError("User does not exist")
目的是引用验证时其他的键
一般这种情况,我是在视图函数里处理的了。
@app.route("/update", methods=["POST"])
@use_args(user_update )
def update(args):
.......
# 在这里进行自定义验证。
return True
webargs
对我来说主要还是提取正确字段,后面的数据验证等,可放到视图函数里,或结合marshmallow
使用。
如果发现更好的办法我会补充的。
看了下官方文档,webargs
是可以配置全局验证的。
我根据官方示例写了个Demo,看看是否符合你要求
# coding=utf-8
from flask import Flask
from webargs import fields
from webargs.flaskparser import parser
app = Flask(__name__)
@app.route('/')
def index():
argmap = {"age": fields.Int(), "years_employed": fields.Int()}
result = parser.parse(
argmap,
# 配置全局验证,返回 False 或抛出 ValidationError 异常表示验证失败
validate=lambda args: args["years_employed"] < args["age"]
)
print(result)
return ''
if __name__ == "__main__":
# app.run()
with app.test_client() as client:
response = client.get('/?age=1&years_employed=2')
print(response) # <Response streamed [422 UNPROCESSABLE ENTITY]>
assert response.status_code == 422
response2 = client.get('/?age=2&years_employed=1')
print(response2) # <Response streamed [200 OK]>
assert response2.status_code == 200
1 个赞
首先十分感谢你的回复,还特意查了文档。
其实我之前也看到了这部分文档,但是有一个问题,就是在项目中做参数验时,为了保证代码风格的一致性,肯定要统一编码方式,装饰器的方式是首选,如果再引入
argmap = {"age": fields.Int(), "years_employed": fields.Int()}
result = parser.parse(
argmap,
# 配置全局验证,返回 False 或抛出 ValidationError 异常表示验证失败
validate=lambda args: args["years_employed"] < args["age"]
)
虽然可以解决需要全局验证的问题,但是又不够优雅。
其实该问题在wtforms的方式就很友好,是你在验证当前字段的同时,也可以使用其他字段
class AccountLoginForm(BaseForm):
username = StringField(validators=[DataRequired()])
password = StringField(validators=[DataRequired()])
def validate_account(self, value):
user = User.query.filter_by(username=value.data).first()
if not user:
raise ParameterException(msg='账户不存在')
自定义验证规则时,既可以验证当前字段,还可以通过self来使用其他字段辅助验证,但wtforms对相对复杂格式的json验证支持不是很友好,总之好像都差那么一点