Python flask 学习笔记(三)
2018-12-10 本文已影响0人
酷酷滴小爽哥
一、Web 表单
本小节主要讲解了以下内容:
- WTForms 表单类
- 常见的 HTML 标准字段
- 表单的渲染
test_form.py 这里的 render_template 可以到 form.html 也可以到 form2.html
from flask import Flask, render_template
from forms import LoginForm
app = Flask(__name__)
@app.route('/')
def login():
form = LoginForm()
return render_template('form2.html', form=form)
app.config['SECRET_KEY'] = 'A RANDOM STRING'
if __name__ == '__main__':
app.run(debug=True)
forms.py
"""
表单类
参考文档:http://wtforms.readthedocs.io/en/latest/
字段类型 说明
StringField 文本字段
TextAreaField 多行文本字段
PasswordField 密码文本字段
HiddenField 隐藏文本字段
DateField 文本字段,值为datetime.date格式
DateTimeField 文本字段,值为datetime.datetime格式
IntegerField 文本字段,值为整数
DecimalField 文本字段,值为decimal.Decimal
FloatField 文本字段,值为浮点数
BooleanField 复选框,值为True和False
RadioField 一组单选框
SelectField 下拉列表
SelectMultipleField 下拉列表,可选择多个值
FileField 文件上传字段
SubmitField 表单提交按钮
FormField 把表单作为字段嵌入另一个表单
FieldList 一组指定类型的字段
"""
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, SelectField, RadioField, \
TextAreaField, DateField, BooleanField
from wtforms.validators import DataRequired
from wtforms.widgets import CheckboxInput, PasswordInput
# 表单类
class LoginForm(FlaskForm):
# DataRequired 设置必需填写;render_kw 为对应标签的属性设置参数
username = StringField(label='用户名', validators=[DataRequired()],
description="请输入用户名",
render_kw={"required": "required", "class": "这是选择器"}
)
password = StringField('密码', validators=[DataRequired()], widget=PasswordInput())
language = RadioField('编程语言',choices=[('cpp','C++'), ('py','Python')])
code = TextAreaField('代码')
date = DateField('日期', render_kw={"type" : "date"})
is_checked = BooleanField('是否已经通过验证')
submit = SubmitField('登录')
form.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>form</title>
</head>
<body>
<form>
<div>
{# 通过 (id="id-username") 可以设置对应标签的属性参数 #}
{{ form.username.label }} : {{ form.username(id="id-username")}}
<small>{{ form.username.description }}</small>
</div>
<div>
{{ form.password.label }} : {{ form.password }}
</div>
<div>
{{ form.language.label }}
{% for radio in form.language %}
<label>{{ radio }} {{ radio.label.text }}</label>
{% endfor %}
</div>
<div>
{{ form.code.label }} : {{ form.code }}
</div>
<div>
{{ form.date.label }} : {{ form.date }}
</div>
<div>
{{ form.is_checked.label }} : {{ form.is_checked }}
</div>
<div>
{{ form.submit.label }} : {{ form.submit }}
{# 注意这里的csrf #}
{{ form.csrf_token }}
</div>
</form>
</body>
</html>
form2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>form2</title>
</head>
<body>
<form action="." method="get" accept-charset="utf-8">
{% for field in form %}
{# 如果是隐藏表单域,则不显示label #}
{% if field.type in ['CSRFTokenField', 'HiddenField'] %}
{{ field }}
{% else %}
<div>
{{ field.label }} : {{ field }}
</div>
{% endif %}
{% endfor %}
</form>
</body>
</html>
二、表单的处理
- Form 内置函数的使用
- POST
- GET
- FILES
直观上来说 GET 方式:
好处:分享链接后,别人打开的和你打开的一样
坏处:你的值在链接里,不够隐私
GET POST 方式异同:
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
test_regitst.py
import os
from flask import Flask, render_template, request
from forms import RegistForm, UploadForm
app = Flask(__name__)
# 文件上传目录 os.path.dirname(__file__) 指代当前文件路径,后面加个 medias 指的是,当前路径下的 medias 目录
UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'medias')
@app.route('/regist/', methods=['GET', 'POST'])
def regist():
form = RegistForm()
if form.validate_on_submit():
data = form.data
print(data)
return render_template('regist.html', form=form)
@app.route('/upload/', methods=['GET', 'POST'])
def upload():
form = UploadForm()
if form.validate_on_submit():
print(request.files['image'])
image = form.data['image']
if image:
print(image.filename)
filename = os.path.join(UPLOAD_PATH, image.filename)
print(filename)
image.save(filename)
flash("文件上传成功")
return 'success!'
else:
return 'no file'
else:
print(form.errors)
return render_template('upload.html', form=form)
app.config['SECRET_KEY'] = 'A RANDOM STRING'
if __name__ == '__main__':
app.run(debug=True)
forms.py
需要注意的是 validators
方式是进行后台的验证,而设置 required
的方式或者使用 JavaScript
的方式,只是前端的方式,前端的方式是可以绕过去的。
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, SelectField, RadioField, \
TextAreaField, DateField, BooleanField, PasswordField, FileField
from wtforms.validators import DataRequired
from wtforms.widgets import CheckboxInput, PasswordInput
from validator import passwordValid
class LoginForm(FlaskForm):
username = StringField(label='用户名', validators=[DataRequired()],
description="请输入用户名",
render_kw={"required": "required", "class": "这是选择器"}
)
password = StringField('密码', validators=[DataRequired()], widget=PasswordInput())
language = RadioField('编程语言',choices=[('cpp','C++'), ('py','Python')])
code = TextAreaField('代码')
date = DateField('日期', render_kw={"type" : "date"})
is_checked = BooleanField('是否已经通过验证')
submit = SubmitField('登录')
class RegistForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired()],
render_kw={'required': 'required', 'placeholder': '请输入用户名'},
description='输入邮箱进行注册'
)
password = PasswordField('密码', validators=[DataRequired('请输入密码'), passwordValid])
language = RadioField('编程语言', choices=[('cpp','C++'), ('py','Python')])
class UploadForm(FlaskForm):
image = FileField('文件上传', validators=[DataRequired()],
render_kw={'required': 'required', 'class': 'form-control'}
)
validator.py
from wtforms.validators import ValidationError
def passwordValid(form, field):
password = field.data
if len(password) != 6:
raise ValidationError('密码必须是6位')
if not password.isdigit():
raise ValidationError('密码必须是数字')
return password
regist.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>regist</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='bootstrap/css/bootstrap.min.css', _external=True)}}">
</head>
<body>
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss='alert'>×</button>
{{ message }}
</div>
{% endfor %}
<div class="col-md-6">
<form method="POST" action=".">
<hr>
{{ form.username.label }} {{ form.username }}
<hr>
{{ form.password.label }} {{ form.password }}
<hr>
{{ form.language.label }} {{ form.language }}
<hr>
<b>
{% if form.password.errors %}
{{ form.password.errors }}
{% endif %}
</b>
<hr>
{{ form.csrf_token }}
<button type="submit">提交</button>
</form>
</div>
</div>
<script type="text/javascript" src="{{ url_for('static', filename='jquery.1.10.2.min.js', _external=True) }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js', _external=True) }}"></script>
</body>
</html>
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>upload</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='bootstrap/css/bootstrap.min.css', _external=True) }}">
</head>
<body>
<div class="container">
<div class="col-md-6">
<form action=".", method="post", enctype="multipart/form-data">
<hr>
{{ form.image.label }}
<hr>
{{ form.image }}
<hr>
{{ form.csrf_token }}
<hr>
<button type="submit">上传</button>
</form>
</div>
</div>
<script type="text/javascript" src="{{ url_for('static', filename='jquery.1.10.2.min.js', _external=True)}}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='bootstrap/js/bootstrap.min.js', _external=True) }}"></script>
</body>
</html>