flask_八、表单+表单提交、csrf、表单渲染

表单相关处理

WTForms支持在python中使用类定义表单,然后通过类定义生成对应的HTML代码,这种方式更方便,易于重用。因此,除非是非常简单的程序,或者想让表单的定义更加灵活,否则不会在模板中直接使用HTML编写表单。

一、使用Flask-WTF处理表单

扩展Flask-WTF继承了WTFforms,使用它可以在flask中更方便的使用WTForms。Flask-WTF将表单数据解析、CSRF保护、文件上传等功能与Flask集成。

二、定义WTForms表单

2.1在Template文件夹下新建一个htmlform.html的文件

 

<form method="post">
    <label for="usernamne">Username</label><br>
    <input type="text" name="username" placeholder="Ross Gellar"><br>
    <label for="password">Password</label><br>
    <input type="password" name="password" placeholder="20201013"><br>
    <input id="remember" name="remember" type="checkbox" checked>
    <label for="remember"><small>Remember me</small></label><br>
    <input type="submit" name="submit" value="log in">
</form>

 

 

2.2在最外层新建form.py(根路径下)

# encoding=utf-8
# from flask_wtf import FlaskForm
from wtforms import Form,StringField,PasswordField,BooleanField,SubmitField
from wtforms.validators import DataRequired,Length
class LoginForm(Form):
    username = StringField("Username",validators=[DataRequired()])
    password = PasswordField("Password",validators=[DataRequired()])
    remember = BooleanField("Remember me")
    submit = SubmitField("Log in")

 

2.3前置条件:启动flask之后,安装flask_wtf

1) pipenv shell

2) pipenv install flask_wtf

 

 

 

2.4输出HTML代码

E:\flask_study>py -3
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from wtforms import Form,StringField,PasswordField,BooleanField,SubmitField
>>> from wtforms.validators import DataRequired,length
>>> class LoginForm(Form):
...     username = StringField("Username",validators=[DataRequired()])
...     password = PasswordField("Password",validators=[DataRequired()])
...     remember = BooleanField("Remember me")
...     submit = SubmitField("Log in")

 

 

 

 

 

>>> form = LoginForm() #实例化
>>> form.username #调字段属性
<wtforms.fields.core.StringField object at 0x000002281B944D30>
>>> form.username()
'<input id="username" name="username" required type="text" value="">'
>>> form.password()
'<input id="password" name="password" required type="password" value="">'
>>> form.remember()
'<input id="remember" name="remember" type="checkbox" value="y">'
>>> form.submit()
'<input id="submit" name="submit" type="submit" value="Log in">'
>>> form.username.label

 

 

 

 

 

 

Label('username', 'Username')
>>> form.username.label()
'<label for="username">Username</label>'
>>> form.submit.label
Label('submit', 'Log in')
>>> form.submit.label()
'<label for="submit">Log in</label>'
>>> 

 

 

字段类

说明

对应的HTML表示

BooleanField

复选框,值会被处理为True或False

<input type=”checkbox”>

DateField

文本字段,值会被处理为datetime.date对象

<input type=”text”>

DateTimeField

文本字段,值会被处理为datetime.datetime对象

<input type=”text”>

FileField

文件上传字段

<input type=”file”>

FloatField

浮点数字段,值会被处理为浮点型

<input type=”text”>

IntegerField

整数字段,值会被处理为整型

<input type=”text”>

RadioField

一组单选按钮

<input type=”radio”>

selectField

下拉列表

<select><option></option></select>

SelectMultipleField

多选下拉列表

<select multiple><option></option></select>

SubmitField

提交按钮

<input type=”submit”>

StringField

文本字段

<input type=”text”>

HiddenField

隐藏文本字段

<input type=”hidden”>

PasswordField

密码文本字段

<input type=”password”>

TextAreaField

多行文本字段

<textarea></textarea>

 

三、字段类构造方法接受的常用参数

通过实例化字段类时传入的参数,我们可以对字段进行设置,字段类构造方法接受的常用参数如下表:

参数

说明

label

字段标签<label>的值,也就是渲染后显示在输入字段前的文字

render_kw

一个字典,用来设置对应的HTML <input>标签的属性,比如传入{‘placeholder’: ‘Your Name’},渲染后的HTML代码会将<input>标签的placeholder属性设为YourName

validators

一个列表,包含一系列验证器,会在表单提交后被逐一调用验证表单数据

default

字符串或可调用对象,用来为表单字段设置默认值

 

四、常用的验证器

在WTForms中,验证器(validator是一系列用于验证字段数据的类,我们在实例化字段类时使用validators关键字来指定附加的验证器列表。

验证器从wtforms.validators模块中导入,常用的验证器,如下表:

验证器

说明

DataRequired(message=None)

验证数据是否有效

Email(message=None)

验证Email地址

EqualTo(filename, message=None)

验证两个字段值是否相同

InputRequired(message=None)

验证是否有数据

Length(min=-1, max=-1, message=None)

验证输入值长度是否在给定范围内

NumberRange(min=None, max=None, message=None)

验证输入数字是否在给定范围内

Optional(strip_whitespace=True)

允许输入值为空,并跳过其他验证

Regexp(regex, flags=0, message=None)

使用正则表达式验证输入值

URL(require_tld=True, message=None)

验证URL

AnyOf(values, message=None, values_formatter=None)

确保输入值在可选值列表中

NoneOf(values, message=None, values_formatter=None)

确保输入值不在可选值列表中

 

五、示例

5.1更新form.py

# encoding=utf-8
from flask_wtf import FlaskForm
from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length

class LoginForm(FlaskForm):
    username = StringField("Username", validators=[DataRequired()])
    password = PasswordField("Password", validators=[DataRequired()])
    remember = BooleanField("Remember me")
    submit = SubmitField("Log in")

 

5.2再次更新form.py的内容

# encoding=utf-8
from flask_wtf import FlaskForm
from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length

class LoginForm(FlaskForm):
    username = StringField("validate_Username", render_kw={'placeholder':'Your Username'})
    password = PasswordField("Password", validators=[DataRequired(),Length(8,128)])
    remember = BooleanField("Remember me")
    submit = SubmitField("Log in")

 

5.3实例化的时候会报错(如下)

form = LoginForm()

 

 

 

5.3.1解决:(激活上下文)

>>> from app import app

>>> app.test_request_context("/html")

<RequestContext 'http://localhost/html' [GET] of app>

>>>

>>>

>>> app.test_request_context('/html').push()

 

5.3.2问题解决后的效果

 

CSRF的保护处理(flask_wtf需要)

来判断请求是否来自自己的网站

跨站请求伪造,生成令牌token

进行令牌保护

 

 

 

 六、Csrf处理的例子(传入表单类实例)

 

6.1app.py文件内容

 

# 传入表单类实例
# encoding=utf-8
from flask import Flask,render_template,flash
import os
from form import LoginForm
from flask import request

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'secret string')

app.config['WTF_CSRF_ENABLED'] = False

@app.route('/form',methods=['GET','POST'])
def basic():
    form=LoginForm()
    return render_template('htmlform.html',form=form)

@app.route('/bootstrap',methods=['GET','POST'])
def bootstrap():
    print("request: %s" % request)
    print("request.url: %s" % request.url)
    print("request.form: %s" % request.form)
    print("request.data: %s" % request.data)
    print("request.headers: %s" % request.headers)

if __name__ == "__main__":
    app.run(debug=True)

 

6.2htmlform.html文件内容

 

<form method="post">
    <label for="usernamne">Username</label><br>
    <input type="text" name="username" placeholder="Ross Gellar"><br>
    <label for="password">Password</label><br>
    <input type="password" name="password" placeholder="20201013"><br>
    <input id="remember" name="remember" type="checkbox" checked>
    <label for="remember"><small>Remember me</small></label><br>
    <input type="submit" name="submit" value="log in">
</form>

 

 

6.3form.py文件内容

 

# encoding=utf-8
from flask_wtf import FlaskForm
from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length

class LoginForm(FlaskForm):
    username = StringField("validate_Username", render_kw={'placeholder':'Your Username'})
    password = PasswordField("Password", validators=[DataRequired(),Length(8,128)])
    remember = BooleanField("Remember me")
    submit = SubmitField("Log in")

 

 

6.4运行结果

 

 

七、Csrf生效的例子

 

7.1新建bootstrap.html文件

内容如下(继承于baseform.html

 

 

 

{% extends 'baseForm.html'%}
{% block styles %}
    <link rel="stylesheet" href="{{ url_for('static',filename='style.css')}}">
{% endblock %}
{% block content %}
    <h1 class='display-4'>Bootstrap Style</h1>
    <form method="post">
        {{ form.csrf_token }}
        <div class="form-group">
            {{ form.username.label }}
            {{form.username(class='form-control',required='')}}
        </div>
        <div class="form-group">
            {{ form.password.label }}
            {{ form.password(class='form-control') }}
        </div>

 

7.2更新htmlform.html

 

<form method='post'>
    {{ form.csrf_token }}<!-- 渲染CSRF令牌隐藏字段 -->
    {{ form.username.label }}{{ form.username }}<br>
    {{ form.password.label }}{{ form.password }}<br>
    {{ form.remember }}{{ form.remember.label }}<br>
    {{ form.submit }}<br>
</form>

 

 

7.3App.py更新

 

# 传入表单类实例
# encoding=utf-8
from flask import Flask,render_template,flash
import os
from form import LoginForm
from flask import request

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'secret string')

app.config['WTF_CSRF_ENABLED'] = False # 该值默认是true

@app.route('/form',methods=['GET','POST'])
def basic():
    form=LoginForm()
    return render_template('htmlform.html',form=form)

@app.route('/bootstrap',methods=['GET','POST'])
def bootstrap():
    print("request: %s" % request)
    print("request.url: %s" % request.url)
    print("request.form: %s" % request.form)
    print("request.data: %s" % request.data)
    print("request.headers: %s" % request.headers)

    form = LoginForm()
    return render_template('bootstrap.html',form=form)
if __name__ == "__main__":
    app.run(debug=True)

 

 

7.4运行结果(form

 

 

7.5源码效果

 

 

7.6App.py注释掉secret_key的效果

 

 

7.7网页源码的效果

 

 八、在模板中渲染表单——用Bootstrap风格

8.1App.py文件内容

 

# 传入表单类实例
# encoding=utf-8
from flask import Flask,render_template,flash
import os
from form import LoginForm
from flask import request

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'secret string')

# app.config['WTF_CSRF_ENABLED'] = False

@app.route('/form',methods=['GET','POST'])
def basic():
    form=LoginForm()
    return render_template('htmlform.html',form=form)

@app.route('/bootstrap',methods=['GET','POST'])
def bootstrap():
    print("request: %s" % request)
    print("request.url: %s" % request.url)
    print("request.form: %s" % request.form)
    print("request.data: %s" % request.data)
    print("request.headers: %s" % request.headers)

    form = LoginForm()
    return render_template('bootstrap.html',form=form)
if __name__ == "__main__":
    app.run(debug=True)

 

 

8.2Template下的htmlform.html

 

<form method='post'>
    {{ form.csrf_token }}<!-- 渲染CSRF令牌隐藏字段 -->
    {{ form.username.label }}{{ form.username }}<br>
    {{ form.password.label }}{{ form.password }}<br>
    {{ form.remember }}{{ form.remember.label }}<br>
    {{ form.submit }}<br>
</form>

 

 

8.3template下的bootstrap文件

 

{% extends 'baseForm.html'%}
{% block styles %}
    <link rel="stylesheet" href="{{ url_for('static',filename='style.css')}}">
{% endblock %}
{% block content %}
    <h1 class='display-4'>Bootstrap Style Form</h1>
    <form method="post">
        {{ form.csrf_token }}
        <div class="form-group">
            {{ form.username.label }}
            {{form.username(class='form-control',required='')}}
        </div>
        <div class="form-group">
            {{ form.password.label }}
            {{ form.password(class='form-control') }}
        </div>
        <div class="form-check">
            {{ form.remember(class='form-check-input') }}
            {{ form.remember.label }}
        </div>
        {{ form.submit(class='btn btn-primary') }}
    </form>
{% endblock content %}

 

8.4Template下的baseform文件——该文件内容不全所以看不到效果

 

<!DOCTYPE html>
<html lang="en">
<head>
    {% block head %}
        {% block metas %}
            <meta charset="utf-8">
        {% endblock metas%}
        <title>
            {% block title %}
                Form = HelloFlask
            {% endblock title %}
        </title>
        <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='favi')}}"
        {% block style %}
            <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename ='s')}}"
        {% endblock styles %}
    {% endblock head %}
</head>
<body>

<nav>
    {% block nav %}
        <u1>
            <li><a href="{{ url_for('basic') }}">Home </a></li>
        </u1>
    {% endblock %}
</nav>

<main>
    {% for message in get_flashed_messages() %}
        <div class="alert">
            {{ message }}
        </div>
    {% endfor %}
    {% block content %}{% endblock %}
</main>
<footer>
    {% block footer %}
    {% endblock %}
</footer>
{% block scripts %}{% endblock %}
</body>
</html>

 

 

8.5主文件下的form.py文件内容

 

# encoding=utf-8
from flask_wtf import FlaskForm
from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length

class LoginForm(FlaskForm):
    username = StringField("validate_Username", render_kw={'placeholder':'Your Username'})
    password = PasswordField("Password", validators=[DataRequired(),Length(8,128)])
    remember = BooleanField("Remember me")
    submit = SubmitField("Log in")

 

 

8.6Static下的style.css文件

 

body{
    margin:auto;
    width:750px;
}

img{
    max-width:710px;
}
nav u1{
    list-style-type:none;
    margin:();
    padding:();
    overflow:hidden;
    background-color:#333;

nav li{
    float:left;
}

nav li.a{
    display:block;
    color:white;
    text-align:center;
    padding:14px 16px;
    text-decoration:none;
}

 

 

8.7在static文件夹下新建一个style.css的文件

 

body{
    margin:auto;
    width:750px;
}

img{
    max-width:710px;
}
nav u1{
    list-style-type:none;
    margin:();
    padding:();
    overflow:hidden;
    background-color:#333;

nav li{
    float:left;
}

nav li.a{
    display:block;
    color:white;
    text-align:center;
    padding:14px 16px;
    text-decoration:none;
}

 

 

8.8最后的提交表单

 

posted @ 2022-04-26 00:41  翻滚的小强  阅读(376)  评论(0)    收藏  举报