表单提交

# 表单提交

### 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">&times;</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>
  ```

### 练习:

- 完成用户的注册登录功能
原文地址:https://www.cnblogs.com/liangliangzz/p/10221979.html