WTForms

WTForms是一个支持多个web框架的form组件,主要用于生成HTML标签,对用户请求数据进行验证。

安装

pip install wtforms

使用

用户注册示例

from flask import Flask
from flask import request
from flask import render_template
from wtforms import Form
from wtforms.fields import simple
from wtforms.fields import core
from wtforms import validators

app = Flask(__name__)


class RegisterForm(Form):
    user = simple.StringField(
        label='用户名',
        validators=[
            validators.DataRequired(message='用户名不能为空'),
            validators.Length(min=6, max=16, message='用户名的长度为6-16'),
        ],
    )
    pwd = simple.PasswordField(
        label='密码',
        validators=[
            validators.DataRequired(message='密码不能为空'),
            validators.Regexp(
                regex=r'(?=.*\d)(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,16}',
                message='密码中必须包含字母、数字、特殊字符,至少8个字符,最多16个字符',
            )
        ],
    )
    pwd_confirm = simple.PasswordField(
        label='确认密码',
        validators=[
            validators.DataRequired(message='密码不能为空'),
            validators.EqualTo('pwd', message='两次密码输入不一致')
        ],
    )
    email = simple.StringField(
        label='邮箱',
        validators=[
            validators.DataRequired(message='邮箱不能为空'),
            validators.Email('邮箱格式错误'),
        ]
    )
    gender = core.RadioField(
        label='性别',
        choices=[(1,'男'),(2,'女')],
        validators = [validators.DataRequired(message='性别不能为空')],
        coerce=int                  # 将提交的字符串类型的数据,转换成int类型
    )

    city = core.SelectField(
        label='城市',
        choices=[
            ('bj','北京'),
            ('wh','武汉'),
            ('sh','上海'),
        ],
        validators=[validators.DataRequired(message='城市不能为空')],
    )
    hobby = core.SelectMultipleField(
        label='爱好',
        choices=[
            (1, '写代码'),
            (2, '睡觉'),
            (3, '吃饭'),
        ],
        validators=[validators.DataRequired(message='爱好不能为空')],
        coerce=int,
        default=[1, 2]
    )


    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self._fields.items():
            if name == 'gender':
                continue
            field.render_kw = {"class":"form-control"}


@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == "GET":
        form = RegisterForm(data={'city': 'bj'})
        return render_template('register.html', form=form)

    if request.method == 'POST':
        form = RegisterForm(formdata=request.form)
        if form.validate():
            print(form.data)
            return '验证成功'
        else:
            return render_template('register.html', form=form)


if __name__ == '__main__':
    app.run()

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style>
        ul{
            margin: 0;
            padding: 0;
            list-style-type: none;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <form class="form-horizontal col-md-8 col-md-offset-2" action="" method="post" novalidate>
            {% for item in form %}
            <div class="form-group">
                <label for="{{ item.id }}" class="col-sm-2 control-label">{{item.label}}:</label>
                <div class="col-sm-10">
                    {{ item }}
                    <span style="color: red">{{item.errors.0}}</span>
                </div>
            </div>
            {% endfor%}
            <div class="text-center">
                <input type="submit" value="提交" class="btn btn-success">
            </div>
        </form>
    </div>
</div>
</body>
</html>

CSRF_token

from wtforms.csrf.core import CSRF
from hashlib import md5


class MyCSRF(CSRF):
    def setup_form(self, form):
        self.csrf_context = form.meta.csrf_context()
        self.csrf_secret = form.meta.csrf_secret
        return super().setup_form(form)

    def generate_csrf_token(self, csrf_token):
        gid = self.csrf_secret + self.csrf_context
        token = md5(gid.encode('utf-8')).hexdigest()
        return token

    def validate_csrf_token(self, form, field):
        print(field.data, field.current_token)
        if field.data != field.current_token:
            raise ValueError('Invalid CSRF')


class LoginForm(Form):
    user = simple.StringField(
        render_kw={
            'class': 'xxx',
            'placeholder': '请输入用户名'
        },
        validators=[
            validators.DataRequired(message='用户名不能为空'),
            validators.Length(min=6, max=16, message='用户名长度在5-16位')
        ]
    )

    pwd = simple.PasswordField(
        render_kw={
            'class': 'xxx',
            'placeholder': '请输入密码'
        },
        validators=[
            validators.DataRequired(message='密码不能为空'),
            validators.Regexp(
                regex=r'(?=.*\d)(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,16}',
                message='密码中必须包含字母、数字、特殊字符,至少8个字符,最多16个字符',
            )
        ]
    )

    class Meta:
        csrf = True
        csrf_field_name = 'csrf_token'
        csrf_secret = 'xxxxxx'
        csrf_context = lambda x: request.url
        csrf_class = MyCSRF

模板文件中,在form标签内添加一行

{{ form.csrf_token }}

钩子函数

validate_字段名

def validate_user(self, field):
    print(field.data)
    if field.data != 'xxxxxx':
        # raise validators.ValidationError('用户名不是xxxxxx')

        # 当前字段不再进行后续规则验证
        raise validators.StopValidation('用户名不是xxxxxx')
posted @ 2020-06-04 17:35  _Otis  阅读(182)  评论(0编辑  收藏  举报