Python Flask中表单验证的问题?

最近在学习python的flask框架,在表单验证的时候遇到了一些困惑,现提出来,然望大家可以给我解答下。

1.wtforms的表单生成和表单验证一般都是一起用的,但是现在我己经有了前端模板,页面己经写好,我只需要使用表单验证功能,这样的话该如何使用呢?

2.如果要做成前后端分离的状态,前端用ajax提交,后端需要对所提交的数据做验证后返回结果,这样的话该如何处理?是可以直接使用wtforms还是有相应的别的库可以使用, 还是必须要自己写呢?

3.看了wtforms的使用方法,貌似验证都是基于表单验证的,这样的话我如果在api中又如何使用呢?

回复
阅读 9.6k
5 个回答

Wtforms的代码可以hack一下,就可以做json数据校验了。可以看这里zerqu关于wtforms的使用。也可以在我正在联手的项目中看到collector

class BaseForm(Form):
    @classmethod
    def create_api_json(cls, obj=None):
        formdata = MultiDict(request.get_json())
        form = cls(formdata=formdata, obj=obj, csrf_enabled=False)
        if not form.validate():
            raise FormError(form)
        return form
        
     def create(self):
         pass
 
class NewsForm(BaseForm):
    title = StringField(
        label="标题",
        validators=[
            DataRequired(),
            Unique(News, News.title, '该条新闻标题已经存在')
        ]
    )
    url = StringField(
        label="链接",
        validators=[
            DataRequired(),
            URL(),
            Unique(News, News.url, '该条新闻链接已经存在')
        ]
    )
    tags = TagListField(label="标签")
    site_id = IntegerField(label="站点ID")
    site_name = StringField(label="站点名称")
    site_url = StringField(label="站点链接", validators=[])
    created_at = DateTimeField(label="创建时间")
    content = TextAreaField(label="正文")
    content_html = TextAreaField(label="富文本正文")

## 使用
@app.route('/api/', methods=['POST'])
def post(self):
    form = NewsForm.create_api_json()
    item = form.create()
    return jsonify(item)    

感觉题主想复杂了,把简单的问题复杂化了。
既然想做前后端分离,就使用restful,直接抛弃jinja2,当然,这样的话也就无需使用wtforms了。然后,前端,后端各做个的表单验证即可。

以下是主要支持的library:

Request/Form Input:
    Django
    Webob (Includes Pylons, Google App Engine, Turbogears)
    Werkzeug (Includes Flask, Tipfy)
    any other cgi.FieldStorage-type multidict
Templating Engines:
    Jinja2
    Mako
    Django Templates (To get the full power of WTForms in your templates, use WTForms-        
    Django.)
    Genshi

所以如果你有自己的模板且在上面支持的列表里的话应该稍作修改便可使用。如果你需要前后端分离的话,就不应该用这种前后端一条龙的工具库。如果是想用restful api的话,参考下django REST framework

WTForms本身既可以用来渲染html控件,可以单独用来验证表单,如果要支持JSON,可以用1楼的hack。
我推荐你用flask_wtf,这个插件,这个插件是对wtfoms的进一步封装,支持form,也支持json,CSRF,文件上传。我在项目里,页面渲染和WebService都是用的这个插件。
例子:
form.py

from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField
from wtforms.validators import Length, StopValidation


class MyForm(FlaskForm):
    # 字段
    name = StringField(validators=[Length(min=1, max=20, message="name长度需在1-20个字符间")])
    name2 = IntegerField()
    # 自定义验证
    def validate_age(self, field):
        # 根据name2查询model
        #  ......
        model = None
        if not model:
            # StopValidateion不需要自己捕捉
            raise StopValidation("name2信息不存在")

view.py

@app.route('/api/get_obj_info', methods=["GET", "POST"]):
def get_obj_info():
    form = MyForm()
    
    if request.method == "GET":
        return jsonify({
            # xxxxx
        })
    
    # validate_on_submit 会自动调用“validate_字段”这些验证方法
    # 验证失败后返回表单验证的错误消息
    if form.validate_on_submit():
       
        return jsonify({
            "status": "success",
            "msg": "xxxx"
        })
     # 验证未通过
     return jsonify({
         "status": "failed":
         "msg": "xxxx",
         "error": form.errors
     })

前台POST数据:

    {
        name: "小明",
        name2: "管理"
    }

如果要做前后端分离,做表单验证可以用这个marshmallow https://github.com/marshmallo...

marshmallow除了生成一个可读性很好的类和验证该字段是不是类型符合以外,还支持序列化和反序列化的处理
http://www.dongwm.com/archive...
这里面有简单的介绍
Flask RESTful API开发之序列化与反序列化
https://blog.igevin.info/post...

@apiv1.route('/login/', methods=['post'])
def login():
    params_dict = {
        'username': request.args.get('username', None),
        'password': request.args.get('password', None),
    }
    # 验证数据
    result, errors = UserValidation().load(params_dict)

    if errors:
        return jsonify({'code': 0, 'msg': errors})
 
    count = User.select().where(
        (User.username == params_dict['username']) & (User.password == params_dict['password'])).count()
    if count > 0:
        return jsonify({'code': 1, 'msg': '登录成功'})

    return jsonify({'code': 1, 'msg': '用户名或者密码错误'})

UserValidation类
from marshmallow import Schema, fields, validates, ValidationError, post_load
class UserValidation(Schema):
    """
    定义要验证的属性
    """
    username = fields.String(required=True)
    password = fields.String(required=True)
推荐问题
宣传栏