zoukankan      html  css  js  c++  java
  • Flask-1-08--表单

    web表单是web应用程序的基本功能。

    它是HTML页面中负责数据采集的部件。表单有三个部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。

    无论前端是否校验了表单数据的安全性合法性,但是后端也是需要有一套单独的校验逻辑,因为如果有人不是通过你前端页面给后端发数据,后端还没有校验就是很麻烦的事情,在Flask中有处理表单的插件,非常简便,就是Flask-wtf,它封装了WTForms,并且它有验证表单数据的功能

    WTForms支持的HTML标准字段

    字段对象

    说明

    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

    一组指定类型的字段

     

    WTForms常用验证函数

    验证函数

    说明

    DataRequired

    确保字段中有数据

    EqualTo

    比较两个字段的值,常用于比较两次密码输入

    Length

    验证输入的字符串长度

    NumberRange

    验证输入的值在数字范围内

    URL

    验证URL

    AnyOf

    验证输入值在可选列表中

    NoneOf

    验证输入值不在可选列表中

    注意:使用Flask-WTF需要配置参数SECRET_KEY。CSRF_ENABLED是为了CSRF(跨站请求伪造)保护。 SECRET_KEY用来生成加密令牌,当CSRF激活的时候,该设置会根据设置的密匙生成加密令牌。

    接下来通过一个简单的案例,来使用这个WTF,创建一个wtf_demo.py的文件

    使用流程:首先定义一个表单的类,继承自FlaskForm在这个类,在类中创建字段,分别导入需要的字段的类[比如用户名导入StringField,密码导入PasswordField...根据自己的需求导入就好],准备就基本完成,接下来定义一个视图,在视图中创建表单对象,也就是你刚才创建的类对象,完成后返回你指定的模板文件,和表单对象即可,这里我们创建的表单对象为form

     1 # coding:utf-8
     2 from flask import Flask, render_template, redirect, url_for, session
     3 from flask_wtf import FlaskForm
     4 from wtforms import StringField, PasswordField, SubmitField
     5 from wtforms.validators import DataRequired, EqualTo
     6 
     7 import sys
     8 reload(sys)
     9 sys.setdefaultencoding('utf8')
    10 
    11 app = Flask(__name__)
    12 app.config['SECRET_KEY'] = 'asd'
    13 
    14 
    15 # 定义登陆表单
    16 class RegisterForm(FlaskForm):
    17     # 创建需要提交的字段
    18     # validators 是验证器 Datarequired 是不能为空 EqualTo是和谁相等
    19     username = StringField(label=u"用户名", validators=[DataRequired(u'用户名不能为空')])
    20     password = PasswordField(label=u'密码', validators=[DataRequired(u'密码不能为空')])
    21     password2 = PasswordField(label=u'确认密码', validators=[DataRequired(u'确认密码不能为空'), EqualTo('password', u'两次密码不一致')])
    22 
    23     submit = SubmitField(label='提交')
    24 
    25 
    26 @app.route('/register', methods=['post', 'get'])
    27 def register():
    28     # 创建表单对象, 如果是post请求,前端发送了数据,flask会把数据在构造form对象的时候,存放到对象中,所以不用验证是get请求,还是post请求
    29     form = RegisterForm()
    30 
    31     # 判断form中的数据是否合法
    32     # 如果form中的数据完全满足所有的验证器,则返回真,否则返回假
    33     if form.validate_on_submit():
    34         # 表示前端发送的数据合法
    35         # 获取前端发送的数据
    36         uname = form.username.data
    37         pw = form.password.data
    38         pw2 = form.password2.data
    39         print(uname, pw, pw2)
    40         # 添加到session中
    41         session['username'] = uname
    42         # 跳转到index页面
    43         return redirect(url_for("index"))
    44     return render_template('register.html', form=form)
    45 
    46 
    47 @app.route('/index')
    48 def index():
    49     # 将登陆时候设置的session取出
    50     username = session.get('username')
    51     return "%s" % username
    52 
    53 
    54 if __name__ == '__main__':
    55     app.run(debug=True)
    Python代码
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6 </head>
     7 <body>
     8     <form method="post">
     9         {{ form.csrf_token }}
    10 
    11         {{ form.username.label }}
    12         <p>{{ form.username }}</p>
    13         <div>
    14         {% for msg in form.username.errors %}
    15             <p>{{ msg }}</p>
    16         {% endfor %}
    17         </div>
    18         {{ form.password.label }}
    19         <p>{{ form.password }}</p>
    20         {% for msg in form.password.errors %}
    21             <p>{{ msg }}</p>
    22         {% endfor %}
    23 
    24         {{ form.password2.label }}
    25         <p>{{ form.password2 }}</p>
    26         {% for msg in form.password2.errors %}
    27             <p>{{ msg }}</p>
    28         {% endfor %}
    29 
    30         {{ form.submit }}
    31     </form>
    32 </body>
    33 </html>
    HTML代码

    注意:这里一定要记得设置 SECRET_KEY, 后面的值自己定义或者使用Python生成都可以,也需要在HTML页面中,设置csrf_token

    展示结果

    宏、继承、包含:

    类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余。

    Jinja2支持宏,还可以导入宏,需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复。

    定义:

    {#不带参数宏的定义#}
    {% macro input() %}
      <input type="text"
             name="username"
             value=""
             size="30"/>
    {% endmacro %}
    {#使用#}
    {{ input() }}
    {# 带参数宏的定义 #}
    {% macro input(name,value='',type='text',size=20) %}
        <input type="{{ type }}"
               name="{{ name }}"
               value="{{ value }}"
               size="{{ size }}"/>
    {% endmacro %}
    
    {#使用#}
    {{ input(value='name',type='password',size=40)}}

    简单的通过一个示例展示一下到底如何使用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>title</title>
    </head>
    <body>
        {# 不带参数   #}
        {% macro input() %}
            <input type="text" value="" size="30">
        {% endmacro %}
    
        <h1>input 1</h1>
        {{ input() }}
        <h1>input 2</h1>
        {{ input() }}
        {# 带参数   #}
        {% macro input2(type, value, size) %}
            <input type="{{ type }}" value="{{ value }}" size="{{ size }}">
        {% endmacro %}
        <h1>input2 1</h1>
        {{ input2("password", "", 50) }}
        <h1>input2 2</h1>
        {{ input2("password", "", 10) }}
    </body>
    </html>
    # coding:utf-8
    from flask import Flask, render_template
    
    app = Flask(__name__)
    
    
    @app.route("/index")
    def index():
        return render_template("index.html")
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', debug=True)

    这样就可以非常方便的复用我们需要的代码。还有一点要说明,就是带默认参数也是可以的

        {# 带默认参数   #}
        {% macro input3(type="text", value="", size="30") %}
            <input type="{{ type }}" value="{{ value }}" size="{{ size }}">
        {% endmacro %}
    
        <h1>input3 1</h1>
        {{ input3() }}
        <h1>input3 2</h1>
        {{ input3(type='password') }}

    当然在上面我们也看到了jinja2的说明中,是支持宏,还有一句话就是也可以导入宏,下面我们来做一下展示

    首先我们需要定一个文件,来管理我们要定义的宏,这里创建一个macro_input.html

    {% macro input4(type="text", value="", size="44") %}
        <input type="{{ type }}" value="{{ value }}" size="{{ size }}">
    {% endmacro %}

    在模板index.html 中使用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>title</title>
    </head>
    <body>
        ...
        {# 导入宏 #}
        {% import "macro_input.html" as input_func %}
        <h1>input4 1</h1>
        {{ input_func.input4() }}
    
    </body>
    </html>

    展示效果

     

    模板继承:

    模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。

    {% block top %}``{% endblock %}标签定义的内容,相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。

    子模板使用extends指令声明这个模板继承自哪?父模板中定义的块在子模板中被重新定义,在子模板中调用父模板的内容可以使用super()。

    父模板:base.html

      {% block top %}
        顶部菜单
      {% endblock top %}
    
      {% block content %}
      {% endblock content %}
    
      {% block bottom %}
        底部
      {% endblock bottom %}

    子模板:

      {% extends 'base.html' %}
      {% block content %}
       需要填充的内容
      {% endblock content %}
    • 模板继承使用时注意点:

      • 不支持多继承。

      • 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。

      • 不能在一个模板文件中定义多个相同名字的block标签。

      • 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。

    包含(Include)

    Jinja2模板中,除了宏和继承,还支持一种代码重用的功能,叫包含(Include)。它的功能是将另一个模板整个加载到当前模板中,并直接渲染。

    示例:

    include的使用

    {\% include 'hello.html' %}

    包含在使用时,如果包含的模板文件不存在时,程序会抛出TemplateNotFound异常,可以加上ignore missing关键字。如果包含的模板文件不存在,会忽略这条include语句。

    示例:

    include的使用加上关键字ignore missing
    
    {\% include 'hello.html' ignore missing %}
    • 宏、继承、包含:

      • 宏(Macro)、继承(Block)、包含(include)均能实现代码的复用。

      • 继承(Block)的本质是代码替换,一般用来实现多个页面中重复不变的区域。

      • 宏(Macro)的功能类似函数,可以传入参数,需要定义、调用。

      • 包含(include)是直接将目标模板文件整个渲染出来。

     Flask中的特殊变量和方法:在Flask中,有一些特殊的变量和方法是可以在模板文件中直接访问的。

    config 对象:

    {# config 对象就是Flask的config对象,也就是 app.config 对象。#}
    
    {{ config.SQLALCHEMY_DATABASE_URI }}

    request 对象:就是 Flask 中表示当前请求的 request 对象,request对象中保存了一次HTTP请求的一切信息。

    request常用的属性如下:

    属性说明类型
    data 记录请求的数据,并转换为字符串 *
    form 记录请求中的表单数据 MultiDict
    args 记录请求中的查询参数 MultiDict
    cookies 记录请求中的cookie信息 Dict
    headers 记录请求中的报文头 EnvironHeaders
    method 记录请求使用的HTTP方法 GET/POST
    url 记录请求的URL地址 string
    files 记录请求上传的文件 *

    使用

    {{ request.url }}

    url_for 方法:url_for() 会返回传入的路由函数对应的URL,所谓路由函数就是被 app.route() 路由装饰器装饰的函数。如果我们定义的路由函数是带有参数的,则可以将这些参数作为命名参数传入。

    {{ url_for('index') }}
    
    {{ url_for('post', post_id=1024) }}

    get_flashed_messages方法:返回之前在Flask中通过 flash() 传入的信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages() 方法取出。

    {% for message in get_flashed_messages() %}
        {{ message }}
    {% endfor %}

     

  • 相关阅读:
    MVC模式下 provider: SQL Network Interfaces, error: 50
    How to expose a JSON endpoint from a WCF-service
    net 后台任意设置 控件显示和隐藏就OK
    VS编程,快速折叠或者展开代码到 #region 级别的设置方法。
    java进阶(18)--Enum枚举
    java进阶(17)--Random
    java进阶(16)--System常用方法总结
    java进阶(15)--DecimalFormat、BigDecimal
    java进阶(14)--日期时间处理
    java进阶(13)--int、String、Integer互相转换
  • 原文地址:https://www.cnblogs.com/Hannibal-2018/p/11308207.html
Copyright © 2011-2022 走看看