• Flask


    Flask - WTF和WTForms创建表单

    一. Flask-WTF

    Flask-WTF是集成WTForms,并带有 csrf 令牌的安全表单和全局的 csrf 保护的功能。
    每次我们在建立表单所创建的类都是继承与flask_wtf中的FlaskForm,而FlaskForm是继承WTForms中forms。

    1.创建基础表单

    class LoginForm(FlaskForm):
        username = StringField()
        password = PasswordField()
        remember_me = BooleanField(label='Keep me logged in')
    

    2.CSRF保护

    任何使用FlaskForm创建的表单发送请求,都会有CSRF的全部保护,在对应的template中HTML渲染表单时,可以加入form.csrf_token:

    <form method="post">
        {{ form.csrf_token }}
    </form>
    

    但是如果模板中没有表单,则可以使用一个隐藏的input标签加入csrf_token。

    <form method="post">
        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
    </form>
    

    3.验证表单

    在视图处理程序中验证请求:

    def login():
        form = LoginForm()
        if form.validate_on_submit():
            return redirect('/success')
        return render_template('login.html', form=form)
    
    # 使用validate_on_submit 来检查是否是一个 POST 请求并且请求是否有效。
    

    或者下面这种方式:

    new_lf = LoginForm(formdata=request.form)
            if new_lf.validate():
                return "登陆成功"
            else:
                return render_template("login.html", lf=new_lf)
    

    4.文件上传

    Flask-WTF 提供 FileField 来处理文件上传,它在表单提交后,自动从 flask.request.files 中抽取数据。FileField 的 data 属性是一个 Werkzeug FileStorage 实例。

    from werkzeug import secure_filename
    from flask_wtf.file import FileField
    
    class PhotoForm(Form):
        photo = FileField('Your photo')
    
    @app.route('/upload/', methods=('GET', 'POST'))
    def upload():
        form = PhotoForm()
        if form.validate_on_submit():
            filename = secure_filename(form.photo.data.filename)
            form.photo.data.save('uploads/' + filename)
        else:
            filename = None
        return render_template('upload.html', form=form, filename=filename)
    

    注意:在 HTML 表单的 enctype 设置成 multipart/form-data,如下:

    5.验证码

    Flask-WTF 通过 RecaptchaField 也提供对验证码的支持:

    rom flask_wtf import Form, RecaptchaField
    from wtforms import TextField
    
    class SignupForm(Form):
        username = TextField('Username')
        recaptcha = RecaptchaField()
    

    还需要配置一下信息:

    # 字段					# 配置
    
    RECAPTCHA_PUBLIC_KEY	# 必须公钥
    
    RECAPTCHA_PRIVATE_KEY	# 必须私钥
    
    RECAPTCHA_API_SERVER	# 可选验证码API服务器
    
    RECAPTCHA_PARAMETERS	# 可选 一个 JavaScript(api.js)参数的字典
    
    RECAPTCHA_DATA_ATTRS	# 可选 一个数据属性项列表 https://developers.google.com/recaptcha/docs/display
    

    二. WTForms

    WTForms是一个Flask集成的框架,或者是说库。用于处理浏览器表单提交的数据。它在Flask-WTF 的基础上扩展并添加了一些随手即得的精巧的帮助函数,这些函数将会使在 Flask 里使用表单更加有趣。

    1. field字段

    WTForms支持HTML字段:

    字段类型:			说明:
    
    StringFidle			文本字段, 相当于type类型为text的input标签
    
    TextAreaField		多行文本字段
    
    PasswordField		密码文本字段
    
    HiddenField			隐藏文本字段
    
    DateField			文本字段, 值为datetime.date格式
    
    DateTimeFieeld		文本字段, 值为datetime.datetime格式
    
    IntegerField		文本字段, 值为整数
    
    DecimalField		文本字段, 值为decimal.Decimal
    
    FloatField			文本字段, 值为浮点数
    
    BooleanField		复选框, 值为True 和 False
    
    RadioField			一组单选框
    
    SelectField			下拉列表
    
    SelectMultipleField	下拉列表, 可选择多个值
    
    FileField			文件上传字段
    
    SubmitField			表单提交按钮
    
    FormFiled			把表单作为字段嵌入另一个表单
    
    FieldList			子组指定类型的字段
    

    2.Validators验证器

    WTForms可以支持很多表单的验证函数:

    Email
    验证是电子邮件地址
    
    
    EqualTo
    比较两个字段的值; 常用于要求输入两次密钥进行确认的情况
    
    
    IPAddress
    验证IPv4网络地址
    
    
    Length
    验证输入字符串的长度
    
    
    NumberRange
    验证输入的值在数字范围内
    
    
    Optional
    无输入值时跳过其它验证函数
    
    
    DataRequired
    确保字段中有数据
    
    
    Regexp
    使用正则表达式验证输入值
    
    
    URL
    验证url
    
    
    AnyOf
    确保输入值在可选值列表中
    
    
    NoneOf
    确保输入值不在可选列表中
    

    3.自定义Validators验证器

    第一种: in-line validator(内联验证器)

    也就是自定义一个验证函数,在定义表单类的时候,在对应的字段中加入该函数进行认证。下面的my_length_check函数就是用于判name字段长度不能超过50.

    def my_length_check(form, field):
        if len(field.data) > 50:
            raise ValidationError('Field must be less than 50 characters')
    
    class MyForm(Form):
        name = StringField('Name', [InputRequired(), my_length_check])
    

    第二种:通用且可重用的验证函数

    一般是以validate开头,加上下划线再加上对应的field字段(validate_filed),浏览器在提交表单数据时,会自动识别对应字段所有的验证器,然后执行验证器进行判断。

    class RegistrationForm(FlaskForm):
        email = StringField('Email', validators=[DataRequired(), Length(1, 60), Email()])
        username = StringField('Username', validators=[DataRequired(), Length(1, 60),
            Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0, 'username must have only letters, numbers dots or underscores')])
        password = PasswordField('Password', validators=[DataRequired(), EqualTo('password2', message='password must match')])
        password2 = PasswordField('Confirm password', validators=[DataRequired()])
    
        def validate_email(self, field):
            if User.objects.filter(email=field.data).count() > 0:
                raise ValidationError('Email already registered')
    
        def validate_username(self, field):
            if User.objects.filter(username=field.data).count() > 0:
                raise ValidationError('Username has exist')
    

    第三种:比较高级的validators

    class Length(object):
        def __init__(self, min=-1, max=-1, message=None):
            self.min = min
            self.max = max
            if not message:
                message = u'Field must be between %i and %i characters long.' % (min, max)
            self.message = message
    
        def __call__(self, form, field):
            l = field.data and len(field.data) or 0
            if l < self.min or self.max != -1 and l > self.max:
                raise ValidationError(self.message)
    
    length = Length
    

    4.Widget组件

    下面可以以登录界面为实例:

    login.py

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from flask import Flask, render_template, request, redirect
    from wtforms import Form
    from wtforms import validators
    from wtforms import widgets
    
    class LoginForm(Form):
        name = simple.StringField(
            label='用户名',
            validators=[
                validators.DataRequired(message='用户名不能为空.'),
            ],
            widget=widgets.TextInput(),
            render_kw={'class': 'form-control'}
        )
        pwd = simple.PasswordField(
            label='密码',
            validators=[
                validators.DataRequired(message='密码不能为空.'),
            ],
            widget=widgets.PasswordInput(),
            render_kw={'class': 'form-control'}
        )
    

    三. 简单的登录验证表单实例

    from flask import Flask, request, render_template, redirect
    from wtforms.fields import simple, core
    from wtforms import Form, validators
    
    app = Flask(__name__)
    app.config["DEBUG"] = True
    
    
    class LoginForm(Form):
        username = simple.StringField(
            label="用户名:",
            validators=[
                validators.DataRequired(message="用户名不能为空"),
                validators.Length(min=4, max=10, message="用户名不能小于%(min)d,不能大于%(max)d")
            ],  # 声明校验方式
            id="username",
            # widget=widgets.FileInput(),
            render_kw={"class": "my_class"},
        )
    
        password = simple.PasswordField(
            label="密码:",
            validators=[
                validators.Length(max=10, min=6, message="password不能小于%(min)d,不能大于%(max)d"),
                validators.Regexp("d+", message="密码只能是数字")
            ],
            id="pwd",
            render_kw={"style": "300px;"}
        )
    
        sub = simple.SubmitField(
            label="登陆",
            render_kw={"class": "bs"}
        )
    
    
    @app.route("/login", methods=["GET", "POST"])
    def login():
        if request.method == "GET":
            lf = LoginForm()
            return render_template("login.html", lf=lf)
        else:
            new_lf = LoginForm(formdata=request.form)
            if new_lf.validate():
                return "登陆成功"
            else:
                return render_template("login.html", lf=new_lf)
    
    
    class RegForm(Form):
        username = simple.StringField(
            label="用户名:",
            validators=[
                validators.Length(min=4, max=10, message="用户名不能小于%(min)d,不能大于%(max)d")
            ]
        )
    
        password = simple.PasswordField(
            label="密码:",
            validators=[
                validators.Length(max=10, min=6, message="password不能小于%(min)d,不能大于%(max)d")
            ]
        )
    
        repassword = simple.PasswordField(
            label="确认眼神:",
            validators=[
                validators.EqualTo("password", message="眼神未确认")
            ]
        )
    
        email = simple.StringField(
            label="邮箱",
            validators=[
                validators.Email(message="邮箱格式不符")
            ]
        )
    
        gender = core.RadioField(
            label="性别:",
            choices=[
                (1, "女"),
                (2, "男")
            ],
            coerce=int
        )
    
        hobby = core.SelectMultipleField(
            label="嗜好",
            choices=[
                (1, "小姐姐"),
                (2, "小萝莉"),
                (3, "小正太"),
                (4, "小哥哥")
            ],
            coerce=int
        )
    
        sub = simple.SubmitField(
            label="登陆",
            render_kw={"class": "bs"}
        )
    
    
    @app.route("/reg", methods=["GET", "POST"])
    def reg():
        if request.method == "GET":
            regf = RegForm()
            return render_template("reg.html", regf=regf)
    
        else:
            new_regf = RegForm(formdata=request.form)
            if new_regf.validate():
                print(new_regf.data.get("gender"))
                print(new_regf.data.get("hobby"))
                return new_regf.data.get("username")
            else:
                return render_template("reg.html", regf=new_regf)
    
    
    if __name__ == '__main__':
        app.run()
    

    参考链接:

    1.https://wtforms.readthedocs.io/en/stable/

    2.https://flask-wtf.readthedocs.io/en/stable/

  • 相关阅读:
    一起谈.NET技术,浅析ASP.NET清空缓存时遇到的问题 狼人:
    一起谈.NET技术,.NET平台上的ModelViewPresenter模式实践 狼人:
    一起谈.NET技术,.Net下的分布式缓存从Discuz!NT的缓存设计谈起 狼人:
    一起谈.NET技术,.NET缓存机制探讨与比对 狼人:
    一起谈.NET技术,.Net下的分布式缓存(2)实现分布式缓存同步的手段 狼人:
    一起谈.NET技术,.Net下的分布式缓存(3)如果我们没有缓存会怎么样 狼人:
    newlisp的lambda表达式
    SQL Server2008登录记录怎么删除?
    线段树端点更新 poj 2828 Buy Tickets
    111 History Grading
  • 原文地址:https://www.cnblogs.com/konghui/p/10574970.html
Copyright © 2020-2023  润新知