先来一个中文文档放在最前面。
另外一个博客,表单的一些用法,传送门
然后再是记录~
1.安装
pip install Flask-WTF
2.构建表单模型
from flask_wtf import FlaskForm #引入表单模型
from wtforms import * #引入输入类型
from wtforms.validators import DataRequired,length #引入验证规则
class UserForm(FlaskForm):
name = StringField('name',validators=[DataRequired(),length(min=8,max=8,message='长度固定为8个')])
3 入口app.py文件
from form import UserForm
app.config['SECRET_KEY']='123123SDFASF' #这里是密码种子必须配置,否则出服务器内部错误,他是保护种子。值可以随便填
@app.route('/',methods=['POST','GET']) #表单类必须有POST入口
def hello_world(): #
uform = UserForm() #实例化
if uform.validate_on_submit(): #这里是验证的判断位置,是一次POST提交
print(uform.name) # 打印结果是HTML包括填写内容
print(uform.name.data) #打印结果是我们最需要的内容值可以直接赋值给变量
return '账号是:%s '%(uform.name.data)
return render_template('user.html',uform=uform) #传进去
保护,bootstrap表单基本都自己带了,不用加
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户界面</title>
</head>
<body>
<form action="/" method="POST">
<p>{{ uform.csrf_token}}</p>
<p> {{ uform.name }}{{ uform.name.errors }}</p>
<p><input type="submit" value="提交1"></p>
</form>
</body>
</html>
第一个P包裹的是隐藏保护值,这个是CSRF的保护机制
在bootstrap中设置 全局CSRF设置,这样就开启全局保护了,也就是说在BOOTSTRAP中必须写上这个设置。
from flask_wtf import CSRFProtect
csrf=CSRFProtect(app=app)
不在bootstrap中每个表单按照官方文档说明如下
# 有表单直接添加{{ form.csrf_token }}即可
<form method="post" action="/">
{{ form.csrf_token }}
</form>
#但是如果模板中没有表单,就自己搓一个 CSRF 令牌如下,放里就行,否则会报400错误:
<form method="post" action="/">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>
#AJAX中推荐的方式是在 <meta> 标签中渲染 CSRF 令牌:
<meta name="csrf-token" content="{{ csrf_token() }}">
#在 <script> 标签中渲染同样可行:
<script type="text/javascript">
var csrftoken = "{{ csrf_token() }}"
</script>
#下面的例子采用了在 <meta> 标签渲染的方式, 在 <script> 中渲染会更简单
#无论何时你发送 AJAX POST 请求,为其添加 X-CSRFToken 头:
var csrftoken = $('meta[name=csrf-token]').attr('content')
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken)
}
}
})
下面是下拉列表和单选的写法
这个label标签多使用于表单提问,,label=‘内容’
select1 = SelectMultipleField(label='标签',
choices=[('1', '洗衣粉一达通*5'),
('2', '洗衣液用到够用*5'), ('3', '就怕你不买系列*3'),
('4', '科技')])
sdd=RadioField(label='谁:',choices=[('a','我'),('b','你')])
HTML里边的~~
<p>{{ uform.select1.label }}</p>
<p>{{ uform.select1 }}</p>
<p>{{ uform.sdd.label }}{{ uform.sdd }}</p>
自制验证规则的写法
核心重点:validate_属性名
这个只要写正确就可以直接进入校验位置比如在下面这个类里边:校验名字就是 validate_name
,校验年龄就是validate_age
class UserForm(FlaskForm):
name = StringField(label='姓名',validators=[DataRequired(),Length(min=2,max=12,message='长度固定为8个')])
age = IntegerField(label='年龄')
def validate_age(self,data1): #这里必须传个参数,但可用可不用,我觉得用self更直观方便
print('--------->>>>>',self.age.data) #这里可以看到我们要比对的内容
if self.age.data <500 : #简单判断一下
raise ValidationError('岁数太小,还不到500岁')#抛出一个叫`ValidationError`的异常括号里边写上信息就可以了```
html接收消息
```python
<p>{{ uform.age.label }}{{ uform.age }}{{ uform.age.errors }}</p>
下面存一个bootstrap的快速表单html
{% extends "bootstrap/base.html" %} //首先先继承,很重要
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}首页{% endblock %} //挖坑挖坑
{% block styles %} //样式挖坑
{{ super() }} //继承后再添加
<style>
</style>
{% endblock %}
{% block navbar %} //导航条,去网站上找一找,选个好看的,注意手机端多测试有的屏幕比较小就不显示
{% endblock %}
{% block content %}
{% block newcontent %}
{{ wtf.quick_form(uform) }}
{% endblock %}
{% block footer %}
{% endblock %}
{% endblock %}
其实就是三句话
{% extends "bootstrap/base.html" %} //首先先继承
{% import "bootstrap/wtf.html" as wtf %} //引入表单
{{ wtf.quick_form(uform) }}//在需要位置直接贴上表单类
在快速表单使用中发现这三句还是比较好用的只是单选无法显示标签lable ,多次测试觉得用单选列表代替单选项吧,那个显示是正常的
但是如果需要进行很多调整,比如输出试卷啥的就要
<form class="form form-horizontal" method="post" role="form" action="">
{{ wtf.form_field(uform.name) }}
</form>
可见先要自己添加表单体,然后一行一行添加内容,保持灵活性和样式
额外记录一个需求和实现:一个表单如果需要联合校验的方法,比如一个表单里边可以在四中洗衣液中进行任意选择,但是总数量不能超过20件。
对于这种需求:我我尝试了一下方案是:首先在第一个表单的验证函数里边写个self.all=[ ],建立一个类里边的公共列表,然后在每一个表单的验证部分都添加self.all.append(data.data)来获取这个表单的数量并添加到公共列表里边,然后在最后的那个洗衣夜的位置写一次校验,进行求和判断sum(self.all) 根据结果抛出异常即可,下面这个例程原理是一样的但是需求有一点点修改,参考即可
from flask_wtf import FlaskForm,CSRFProtect
from wtforms import *
from wtforms.validators import DataRequired,Length
class UserForm(FlaskForm):
age2 = SelectField(label='洗衣粉组:立白洗衣液,注意:以下洗衣粉四选一数量填5', choices=[(0,0),(5,5)],validators=[DataRequired()])
age3 = SelectField(label='洗衣粉组:立黑洗衣液', choices=[(0,0),(5,5)],validators=[DataRequired()])
age4 = SelectField(label='洗衣粉组:哈哈洗衣液', choices=[(0,0),(5,5)],validators=[DataRequired()])
age5 = SelectField(label='洗衣粉组:嗯嗯洗衣液',choices=[(0,0),(5,5)], validators=[DataRequired()])
sb = SubmitField()
def validate_age2(self,data):
self.all=[ ]
print('++++++++++++++++++++>>>>' ,data.data)
self.all.append(int(data.data))
def validate_age3(self,data):
self.all.append(int(data.data))
def validate_age4(self,data):
self.all.append(int(data.data))
def validate_age5(self,data):
self.all.append(int(data.data))
if sum(self.all) >5:
raise ValidationError('四个洗衣夜选一种数量5,不能超过5')
##########################################
文件上传部分
先引入FileRequired
FileAllowed
FileField
注意这个 FileField
要引入flask_wtf.file
里边的,
wtforms
类里有同名的别引错成这个了
from flask_wtf.file import FileRequired,FileAllowed,FileField
FileField 是字段类型
FileRequired() 表示验证不能空
FileAllowed([‘jpg’,‘gif’,‘png’],message=‘123123’) 表示验证准许的类型
icon = FileField(label='你的头' ,
validators=[FileRequired(),
FileAllowed(['jpg','gif','png'],message='123123')])
#然后,记得把你的 HTML 表单的 enctype
设置成 multipart/form-data
,既是:
python
<form action="/upload/" method="POST" enctype="multipart/form-data">
下面是保存文件的响应
from werkzeug.utils import secure_filename #文件名校验模块
@app.route('/',methods=['POST','GET'])
def hello_world1():
uform = UserForm()## 看好了我可是有括号的
if uform.validate_on_submit(): # 响应从这里开始
icon=uform.icon.data #首先取出上传的数据
filename =secure_filename(icon.filename) #校验文件名是否合法,我记得不支持中文,用中文就不用这行直接用里边的名字 icon.filename
BASE_DIR=os.path.dirname(os.path.abspath(__file__))#获取当前文件所在目录
UPLOAD_DIR=os.path.join(BASE_DIR,'static')#拼接到静态文件夹上
icon.save(os.path.join(UPLOAD_DIR,filename))#拼接上路径和文件名然后执行保存。
return '成功%s===>%s'
return render_template('base1.html',uform=uform)