• Flask Web——表单


    表单可以提供文本输入框、单选按钮、复选框、按钮等元素供用户提交数据。在Flask项目中,表单除了可以表示传统的HTML标签,还可以验证数据。数据被发送到服务器后,为了防止不法分子绕过前端限制提交非法数据,需要对数据验证。为实现验证功能,需要Flask-WTF插件,使用pip install flask-wtf安装。

    表单验证

    以注册功能为例,验证表单验证功能。首先在templates文件夹中创建register.html文件。

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>注册title>
    head>
    <body>
        <form action="{{ url_for('register') }}" method="POST">
            <table>
                <tr>
                    <td>用户名:td>
                    <td><input type="text" name="username">td>
                tr>
                <tr>
                    <td>邮箱:td>
                    <td><input type="email" name="email">td>
                tr>
                <tr>
                    <td>密码:td>
                    <td><input type="password" name="password">td>
                tr>
                <tr>
                    <td>td>
                    <td><input type="submit" value="提交">td>
                tr>
            table>
        form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    模板写好后,使用视图函数渲染。

    @app.route("/register", methods=['GET','POST'])
    def register():
        if request.method == 'GET':
            return render_template("register.html")
        else:
            pass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    打开https://127.0.0.1:5000/register后,即可看到模板被渲染后的结果:
    在这里插入图片描述
    在这里插入图片描述

    表单类编写

    用户可以在页面中输入信息,但是每个输入的信息字段都有一定的规则要求,如果用户的输入有误,应该在界面中给予及时的提示。这个工作可以在前端由JavaScript完成,但是服务器端也应该做好验证,因为对于有一定技术功底的用户来说,可以通过抓包的形式获取注册时的请求数据,然后通过代码或工具模拟注册,这完全绕开了JavaScript验证。
    服务器端的验证也可以通过WTForms来实现,首先在项目的根路径下创建forms.py。
    forms.py

    from wtforms import Form, StringField
    from wtforms.validators import length, email, equal_to
    
    class RegisterForm(Form):   #所有表单类都必须继承自Form基类
        username = StringField(validators=[length(min=3, max=20, message="请输入正确长度的用户名,不少于3位而不多于20位。")])
        email = StringField(validators=[email(message="请输入正确格式的邮箱!")]) #验证内容是否满足邮箱的格式规则
        password = StringField(validators=[length(min=60, max=20, message="请输入正确长度的密码!")])
        confirm_password = StringField(validators=[equal_to("password",message="两次密码长度不一致!")])
        #👆字段的名称必须和HTML中模板中表单元素的name一致。
        #StringField指的是字符串类型,此外还有IntegerField、FloatField等
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    视图函数中使用表单

    以下以完善register视图函数为例:完善了register视图函数的POST功能,但是仍然不完整。

    @app.route("/register", methods=['GET','POST'])
    def register():
        if request.method == 'GET':
            return render_template("register.html")
        else:
            #request.form时html模板提交上来的表单数据
            form = RegisterForm(request.form)   #需要使用import从刚刚编写的forms.py导入RegisterForm
            #如果表单验证通过
            if form.validate():
                #👇通过form.<字段名>.data获取字段对应的数据
                email = form.email.data
                username = form.username.data
                password = form.username.data
    
                #以下代替把数据保存到数据库中的操作
                print("email:", email)
                print("username:", username)
                print("password:", password)
                return "注册成功!"
            else:
                for errors in form.errors.values():
                    for error in errors:
                        flash(error)
                return redirect(url_for("register"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    渲染表单模板

    WTForms和Flask-WTF都提供了将Python表单对象渲染成HTML表单模板的功能。这里以登录为例,先来实现一个登录的表单类。

    from wtforms import Form, StringField, BooleanField, SubmitField, ValidationError
    from wtforms.validators import length, email, equal_to
    from flask_wtf import FlaskForm
    
    #👇定义一个LoginForm,并使之继承自FlaskForm,FlaskForm的父类是wtforms.Form类
    class LoginForm(FlaskForm):
        email = StringField(label="邮箱", validators=[email(message="请输入正确格式的邮箱!")],render_kw={
            "placeholder":"请输入邮箱"
        })
        password = StringField(label="密码", validators=[length(min=6, max=20, message="请输入正确长度的密码!")],
                               render_kw={"placeholder":"请输入密码"})
        remember = BooleanField(label="记住我:")
        submit = SubmitField(label="提交")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    表单类定义好后,就可以在视图函数中使用了。

    @app.route("/login", methods=['GET', 'POST'])
    def login():
        form = LoginForm(meta={"csrf":False})
        if form.validate_on_submit():
            email = form.email.data
            password = form.password.data
            return redirect('/')    #如果提交成功,重定向至‘/’
        return render_template("login.html",form=form)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    👆如果登录成功,重定向至根路径https://127.0.0.1:5000。接下来可以定义login.html的模板了。

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    <form action="" method="POST">
        <table>
            <tbody>
            <tr>
                <td>{{ form.email.label }}td>
                <td>{{ form.email }}td>
            tr>	#如果有错误,在输入框下显示
            {% for error in form.email.errors %}
            <tr>
                <td>td>
                <td>{{ error }}td>
            tr>
            {% endfor %}
            <tr>	
                <td>{{ form.password.label }}td>
                <td>{{ form.password }}td>
            tr>	#如果有错误,在输入框下显示
            {% for error in form.password.errors %}
            <tr>
                <td>td>
                <td>{{ error }}td>
            tr>
            {% endfor %}
            <tr>
                <td>{{ form.remember.label }}td>
                <td>{{ form.remember() }}td>
            tr>
            <tr>
                <td>td>
                <td>{{ form.submit }}td>
            tr>
            tbody>
        table>
    form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

    CSRF攻击

    通过SCRFProtect可以开启全局防御。

    app = Flask(__name__)
    app.secret_key = "自定的app密钥"
    CSRFProtect(app)
    
    • 1
    • 2
    • 3

    👆在app.py中加入上述代码
    再在register.html模板中加入以下代码:

    <body>
        <form action="{{ url_for('register') }}" method="POST">
            <table>
                <tr>
                    <td>td>
                    <td><input type="hidden" name="csrf_token" value="{{ IjQ0 }}">td>
                tr>
                ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此时再次运行app.py,直接点击提交会出现以下信息:
    在这里插入图片描述
    当然,书中的csrf_token比此处的复杂得多。

  • 相关阅读:
    乱码问题解决
    IDE工具(48) idea常用插件
    Elasticsearch 相关问题总结
    卡尔曼滤波公式理解
    可用于嵌入各种功能的STSPIN820、STSPIN830、STSPIN240、STSPIN233电机驱动器 功率 MOSFET
    Java算法 每日一题(五) 编号209:长度最小的子数组
    【UE】事件分发器 正确使用方法 (如何创建 Bnd Evt Delegate Signature)
    Leetcode 918. Maximum Sum Circular Subarray (单调队列好题)
    appium 2.5.1多进程自动化多台真机测试时候经常提示'exited with code 1'
    Java算法解题小记
  • 原文地址:https://blog.csdn.net/fatfairyyy/article/details/126832176