# 表单提交 ### flask-bootstrap - 说明:在flask中如何使用bootstrap,可以通过此扩展进行解决。 - 安装:`pip install flask-bootstrap` - 使用: ```python from flask_bootstrap import Bootstrap bootstrap = Bootstrap(app) ``` - 模板: ```html {# 继承自bootstrap的基础模板 #} {% extends 'bootstrap/base.html' %} {% block title %}标题{% endblock %} {% block content %} <div class="container"> 内容 </div> {% endblock %} ``` - bootstrap基础模板中的block | block | 说明 | | ------- | ------------------ | | doc | 整个HTML文档 | | html | 整个html标签 | | head | 整个head标签 | | title | 整个title标签 | | metas | 一组meta标签 | | styles | 一组link标签(加载CSS文件) | | body | 整个body标签 | | navbar | 导航条 | | content | 网页内容 | | scripts | 一组script标签(加载JS文件) | > 提示:当重写一个block后,发现原来的显示全没了,很可能是因为没有使用{{ super() }}。 ### 项目基础模板定制 - 从bootstrap官网复制一个顺眼的导航条 - 将`container-fluid`改为`container` - 改为反色导航条,将`navbar-default`改为`navbar-inverse` - 设置为直角:`style="border-radius: 0px;"` - 根据需要定制导航条上的显示内容 ### 加载静态资源 - flask中静态资源默认存放在static目录下,因此目录结构如下: ``` project/ manage.py # 启动控制文件 templates/ # 模板文件目录 static/ # 静态资源目录 img/ css/ js/ favicon.ico ``` - 加载静态资源 ```html {# 基础模板中,加载网站收藏夹小图标 #} {% block head %} {{ super() }} <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}" /> {% endblock %} {# 加载图片资源 #} <img src="{{ url_for('static', filename='img/gyy.jpg') }}" /> {# 加载CSS文件 #} {% block styles %} {{ super() }} <link type="text/css" href="{{ url_for('static', filename='css/common.css') }}" rel="stylesheet" /> {% endblock %} {# 加载JS文件 #} {% block scripts %} {{ super() }} <script type="text/javascript" src="{{ url_for('static', filename='js/common.js') }}"></script> {% endblock %} ``` ### 原生表单 - 准备模板文件`login.html`: ```html <form method="post" action="/check/"> 用户名:<input name="username" /><br /> <input type="submit" /> </form> ``` - 添加视图函数,并渲染模板文件: ```python @app.route('/login/') def login(): return render_template('login.html') ``` - 添加检验视图函数: ```python @app.route('/check/', methods=['POST']) def check(): return '登录成功' ``` - 一个路由接收两种请求: ```python @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') else: # request.form存放了所有的POST请求数据 # return request.form.get('username') # request.values存放了所有GET/POST请求数据 return request.values.get('username') ``` ### flask-wtf - 说明:表单处理的扩展库,提供了CSRF、字段校验等功能,使用非常方便 - 安装:`pip install flask-wtf` - 使用: - 创建表单类 ```python # 导入表单基类 from flask_wtf import FlaskForm # 导入相关字段 from wtforms import StringField, SubmitField # 导入相关验证器 from wtforms.validators import Length # 创建表单类 class NameForm(FlaskForm): name = StringField('用户名', validators=[Length(3, 10, message='用户名长度必须在3~10个字符之间')]) submit = SubmitField('提交') ``` - 添加视图函数,创建表单对象,并渲染模板文件: ```python @app.route('/', methods=['GET', 'POST']) def index(): # 创建表单对象 form = NameForm() # 判断是否是有效的提交 if form.validate_on_submit(): # 提取表单数据 return form.name.data return render_template('form.html', form=form) ``` - 原生渲染表单 ```html <form method="post"> {# CSRF字段 #} {{ form.hidden_tag() }} {{ form.name.label() }}{{ form.name(id='xxx', class='yyy') }} {% for e in form.name.errors %} <div>{{ e }}</div> {% endfor %} {{ form.submit() }} </form> ``` - 使用bootstrap方式进行快速渲染 ```html {# 继承自bootstrap基础模板 #} {% extends 'bootstrap/base.html' %} {# 导入快速渲染的宏 #} {% from 'bootstrap/wtf.html' import quick_form %} {% block content %} <div class="container"> {# 在合适位置快速渲染表单 #} {{ quick_form(form) }} </div> {% endblock %} ``` - POST重定向到GET:因为浏览器会记录最后的请求状态,点击刷新时POST请求会有问题。 ```python @app.route('/', methods=['GET', 'POST']) def index(): # 创建表单对象 form = NameForm() # 判断是否是有效的提交 if form.validate_on_submit(): # 提取表单数据 session['name'] = form.name.data return redirect(url_for('index')) name = session.get('name') return render_template('form2.html', form=form, name=name) ``` - 常见字段类型 | 字段类型 | 说明 | | ------------- | ------------------- | | StringField | 普通文本字段 | | Submit | 提交按钮 | | PasswordField | 密文字段 | | HiddenField | 隐藏字段 | | RadioField | 单选框 | | BooleanField | 复选框 | | FileField | 文件上传 | | SelectField | 下拉框 | | TextAreaField | 文本域 | | IntegerField | 文本字段,值为整数 | | FloatField | 文本字段,值为浮点数 | | DateField | datetime.date类型 | | DateTimeField | datetime.datetime类型 | - 常见验证器 | 验证器 | 说明 | | ------------ | ------------------- | | Length | 规定字符长度 | | DataRequired | 确保字段有值(提示信息与所写的不一致) | | Email | 邮箱地址 | | IPAddress | IP地址 | | NumberRange | 数值的范围 | | URL | 统一资源定位符 | | EqualTo | 验证两个字段的一致性 | | Regexp | 正则验证 | - 自定义验证函数 ```python from wtforms.validators import ValidationError class NameForm(FlaskForm): 。。。 def validate_name(self, field): if len(field.data) < 6: raise ValidationError('用户名不能少于6个字符') ``` > 总结:写字段验证函数,就是写一个'validate_字段名'的函数 ### 消息闪烁 - 说明: 当用户发出请求后,状态发生了改变,需要系统给出警告、提示等信息时,通常是弹出一条消息,指示用户下一步的操作,用户可以手动关闭提示消息。而且整个的过程不会影响页面原有的显示。 - 使用: - 在需要弹出消息时,使用`flash`函数保存闪烁消息 ```python @app.route('/', methods=['GET', 'POST']) def index(): # 创建表单对象 form = NameForm() # 判断是否是有效的提交 if form.validate_on_submit(): last_name = session.get('name') if last_name and form.name.data != last_name: flash('大哥,又换签名了!') # 提取表单数据 session['name'] = form.name.data return redirect(url_for('index')) name = session.get('name') return render_template('form2.html', form=form, name=name) ``` - 在模板文件中显示闪烁消息时,可以通过函数`get_flashed_messages`获取 - 从bootstrap上粘贴一个可消失的警告框 ```html {% for message in get_flashed_messages() %} <div class="alert alert-warning alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span> </button> {{ message }} </div> {% endfor %} ``` ### flask-moment - 说明:专门负责时间本地化显示的扩展库,使用非常方便 - 安装:`pip install flask-moment` - 使用: - python代码 ```python from flask_moment import Moment moment = Moment(app) @app.route('/mom/') def mom(): from datetime import datetime, timedelta current_time = datetime.utcnow() + timedelta(seconds=-60) return render_template('mom.html', current_time=current_time) ``` - 模板文件 ```html {# 加载jQuery #} {{ moment.include_jquery() }} {# 加载moment.js #} {{ moment.include_moment() }} {# 设置语言 #} {{ moment.locale('zh-CN') }} {# 简单的格式化时间显示 #} <div>时间:{{ moment(current_time).format('LLLL') }}</div> <div>时间:{{ moment(current_time).format('LLL') }}</div> <div>时间:{{ moment(current_time).format('LL') }}</div> <div>时间:{{ moment(current_time).format('L') }}</div> {# 自定义格式化显示 #} <div>自定义:{{ moment(current_time).format('YYYY-MM-DD HH:mm:ss') }}</div> {# 显示时间差 #} <div>发表于:{{ moment(current_time).fromNow() }}</div> ``` ### 练习: - 完成用户的注册登录功能