• 【Web开发】Flask框架基础知识


    本篇主要是黑马程序员的Flask快速入门教程的笔记

    Flask简介

    Flask诞生于2010年,是用Python语言基于Werkzeug工具箱编写的轻量级Web开发框架。

    Flask的常用扩展包:

    • Flask-SQLalchemy:操作数据库;
    • Flask-migrate:管理迁移数据库;
    • Flask-Mail:邮件;
    • Flask-WTF:表单;
    • Flask-Bable:提供国际化和本地化支持,翻译;
    • Flask-script:插入脚本;
    • Flask-Login:认证用户状态;
    • Flask-OpenID:认证;
    • Flask-RESTful:开发REST API的工具;
    • Flask-Bootstrap:集成前端Twitter Bootstrap框架;
    • Flask-Moment:本地化日期和时间;
    • Flask-Admin:简单而可扩展的管理接口的框架

    相关文档:
    中文文档:http://docs.jinkan.org/docs/flask/
    英文文档:http://flask.pocoo.org/docs/0.12/

    Flask安装

    pip install flask
    
    • 1

    我安装的版本是Flask 2.1.3

    拓展命令:
    将当前环境打包成requirements.txt

    pip freeze >requirements.txt
    
    • 1

    将需要的环境一起安装:

    pip install -r requirements.txt
    
    • 1

    基本框架

    在Pycharm中,可以直接新建一个Flask模板文件,运行后,可以在浏览器在中输出Hello World。

    在这里插入图片描述

    相关注释如下:

    from flask import Flask
    
    # 指向程序所在的模块
    app = Flask(__name__)
    
    
    # 将路由映射到视图函数index
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    
    
    if __name__ == '__main__':
        # 启动WEB服务器
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    路由请求方式限定

    默认情况下,路由仅支持Get请求方式,可用下

    @app.route('/', methods=['GET', 'POST'])
    def hello_world():
        return 'Hello World!'
    
    • 1
    • 2
    • 3

    路由传递参数

    在路由中使用<>可以传递参数,使用int可以限定整形数据

    @app.route('/orders/')
    def order(order_id):
        print(type(order_id))  # 类型为int
        return 'this is order %d' % order_id
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    Jinja2模板引擎

    Jinja2:是Python下一个被广泛应用的模板引擎,是Flask内置的模板语言。

    简单使用

    Jinja2提供了render_template函数,来渲染html文件。
    下面简单来使用一下:

    先导入render_template

    from flask import Flask, render_template
    
    • 1

    在templates文件夹下新建index.html

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    测试Jinja2
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    进行调用

    @app.route('/', methods=['GET', 'POST'])
    def index():
        return render_template('index.html')
    
    • 1
    • 2
    • 3

    注释

    使用 {# #} 进行可以进行注释

    变量/控制语句

    在路由函数里,可以自定义变量,然后在render_template函数中进行参数传递,例如:

    @app.route('/', methods=['GET', 'POST'])
    def index():
        my_list = [1, 2, 3, 4, 5]
        return render_template('index.html', num_list=my_list)
    
    • 1
    • 2
    • 3
    • 4

    num_list对应html文件中的变量。

    在html中循环输出:
    index.html:

    <body>
    {% for num in num_list %}
        {{ num }}
    {% endfor %}
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    小技巧:先写for,再按Tab可使用代码补全

    输出效果:
    在这里插入图片描述

    过滤器

    过滤器即Flask提供的一些函数,可以直接进行调用简化操作。

    例如:使用lower可以实现字符串转小写, 使用length可以获取列表长度。
    输入:

    <body>
    {#字符串转小写#}
    <p>{{ 'HELLO' | lower }}p>
    {#获取列表长度#}
    <p>{{ [1,2,3,4,5,6] | length }}p>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出:
    在这里插入图片描述
    注:使用连续的|可以同时使用多个过滤器

    更多过滤器总结:

    字符串操作

    • safe:禁用转义
    <p>{{ 'hello' | safe }}</p>
    
    • 1
    • capitalize:把变量值的首字母转成大写,其余字母转小写
    <p>{{ 'hello' | capitalize }}</p>
    
    • 1
    • lower:把值转成小写
    <p>{{ 'HELLO' | lower }}</p>
    
    • 1
    • upper:把值转成大写
    <p>{{ 'hello' | upper }}</p>
    
    • 1
    • title:把值中的每个单词的首字母都转成大写
    <p>{{ 'hello' | title }}</p>
    
    • 1
    • reverse:字符串反转
    <p>{{ 'olleh' | reverse }}</p>
    
    • 1
    • format:格式化输出
    <p>{{ '%s is %d' | format('name',17) }}</p>
    
    • 1
    • striptags:渲染之前把值中所有的HTML标签都删掉
    <p>{{ 'hello' | striptags }}</p>
    
    • 1
    • truncate: 字符串截断
    <p>{{ 'hello every one' | truncate(9)}}</p>
    
    • 1

    列表操作

    • first:取第一个元素
    <p>{{ [1,2,3,4,5,6] | first }}</p>
    
    • 1
    • last:取最后一个元素
    <p>{{ [1,2,3,4,5,6] | last }}</p>
    
    • 1
    • length:获取列表长度
    <p>{{ [1,2,3,4,5,6] | length }}</p>
    
    • 1
    • sum:列表求和
    <p>{{ [1,2,3,4,5,6] | sum }}</p>
    
    • 1
    • sort:列表排序
    <p>{{ [6,2,3,1,5,4] | sort }}</p>
    
    • 1

    语句块过滤

    {% filter upper %}
        一大堆文字
    {% endfilter %}
    
    • 1
    • 2
    • 3

    Flask-WTF表单

    在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,并且它有验证表单数据的功能

    以最常见的登录验证为例,这里以普通实现方式和WTF表单方式实现进行比较。

    普通方式

    html

    <form method="post">
        <label>用户名:</label><input type="text" name="username"><br>
        <label>密码:</label><input type="password" name="password"><br>
        <label>确认密码:</label><input type="password" name="password2"><br>
        <input type="submit" value="提交"><br>
        {% for message in get_flashed_messages() %}
            {{ message }}
        {% endfor %}
    </form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    app.py

    from flask import Flask, render_template, request, flash
    
    # 指向程序所在的模块
    app = Flask(__name__)
    
    # Flask-WTF需要配置参数SECRET_KEY
    app.secret_key = 'zstar'
    
    
    @app.route('/', methods=['GET', 'POST'])
    def hello_world():
        # 1. 判断请求方式是post
        if request.method == 'POST':
            # 2. 获取参数, 并效验参数完整性, 如果有问题就进行flash
            username = request.form.get('username')
            password = request.form.get('password')
            password2 = request.form.get('password2')
            if not all([username, password, password2]):
                flash('params error')
    
            # 3. 效验密码
            elif password != password2:
                flash('password error')
    
            # 4. 没有问题就返回'success'
            else:
                print(username)
                return 'success'
    
        return render_template('index.html')
    
    
    if __name__ == '__main__':
        # 启动WEB服务器
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    代码说明:
    后端使用request.form.get的来获取前端表单数据
    验证主要来验证两次登录输入密码是否一致
    提示信息使用flash来进行映射,前端使用get_flashed_messages来获取映射的信息。

    WTF表单方式

    html

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    <form method="post">
        {#设置csrf_token(python3版本不需要)#}
        {{ form.csrf_token() }}
        {{ form.username.label }}{{ form.username }}<br>
        {{ form.password.label }}{{ form.password }}<br>
        {{ form.password2.label }}{{ form.password2 }}<br>
        {{ form.input }}<br>
        {% for message in get_flashed_messages() %}
            {{ message }}
        {% endfor %}
    form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    app.py

    from imp import reload
    from flask import Flask, render_template, request, flash
    # 导入wtf扩展的表单类
    from flask_wtf import FlaskForm
    
    # 导入自定义表单需要的字段
    from wtforms import SubmitField, StringField, PasswordField
    
    # 导入wtf扩展提供的表单验证器
    from wtforms.validators import DataRequired, EqualTo
    
    # # 解决编码问题
    # import sys
    # reload(sys)
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'zstar'
    
    
    # 自定义表单类,文本字段、密码字段、提交按钮
    # 需要自定义一个表单类
    class RegisterForm(FlaskForm):
        username = StringField('用户名:', validators=[DataRequired()])
        password = PasswordField('密码:', validators=[DataRequired()])
        password2 = PasswordField('确认密码:', validators=[DataRequired(), EqualTo('password', '密码输入不一致')])
        input = SubmitField('提交')
    
    
    # 定义根路由视图函数,生成表单对象,获取表单数据,进行表单数据验证
    @app.route('/form', methods=['GET', 'POST'])
    def form():
        register_form = RegisterForm()
    
        if request.method == 'POST':
            # 调用validate_on_submit方法, 可以一次性执行完所有的验证函数的逻辑
            if register_form.validate_on_submit():
                # 进入这里就表示所有的逻辑都验证成功
                username = request.form.get('username')
                password = request.form.get('password')
                password2 = request.form.get('password2')
                print(username)
                return 'success'
            else:
                flash('参数有误')
    
        return render_template('index.html', form=register_form)
    
    
    if __name__ == '__main__':
        # 启动WEB服务器
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    代码说明:
    使用WTF表单方式的好处是对于密码一致性的不再需要单独进行验证,而是在后端直接将表单封装了成了一个类。
    其中,StringField指定了表单提交的数据类型为String,DataRequired表明该项为必填项,EqualTo封装了两个表单的一致性比较过程,最后调用register_form.validate_on_submit来一次性提交所有的验证逻辑。
    前端方面,通过form可以直接对接到后端定义的表单属性,其中python2需要添加 {{ form.csrf_token() }}来指定表单的token,在python3版本中,实测不需要该语句也能运行。

    WTForms支持的HTML标准字段有下面这些:

    字段对象说明
    StringField文本字段
    TextAreaField多行文本字段
    PasswordField密码文本字段
    HiddenField隐藏文件字段
    DateField文本字段,值为datetime.date文本格式
    DateTimeField文本字段,值为datetime.datetime文本格式
    IntegerField文本字段,值为整数
    DecimalField文本字段,值为decimal.Decimal
    FloatField文本字段,值为浮点数
    BooleanField复选框,值为True和False
    RadioField—组单选框
    SelectField下拉列表
    SelectMutipleField下拉列表,可选择多个值
    FileField文件上传字段
    submitField表单提交按钮
    FormField把表单作为字段嵌入另—个表单
    FieldList—组指定类型的字段

    WTForms常用验证函数:

    验证函数说明
    DataRequired确保字段中有数据
    EqualTo比较两个字段的值,常用于比较两次密码输入
    Length验证输入的字符串长度
    NumberRange验证输入的值在数字范围内
    URL验证URL
    AnyOf验证输入值在可选列表中
    NoneOf验证输入值不在可选列表中

    数据库

    在flask中,可以利用SQLAlchemy来进行数据库的操作。

    SQLAlchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLAlchemy操作的flask扩展。

    flask-sqlalchemy安装

    pip install flask-sqlalchemy
    pip install mysqlclient
    
    • 1
    • 2

    直接安装mysqlclient可能会安装失败,我去官网下了轮子:
    mysqlclient-1.4.6-cp37-cp37m-win_amd64:https://pan.baidu.com/s/1TiLRPUWjQc8HS7ELlGcxHw?pwd=8888

    安装mysql

    安装mysql可以参阅这篇博文:Windows10安装MySQL傻瓜式教程(图文教程)

    使用下面的命令可以启动/停止mysql服务

    # 停止mysql服务
    net stop mysql57 
    # 启动mysql服务
    net start mysql57
    
    • 1
    • 2
    • 3
    • 4

    安装好之后,可以通过Navicat连接本地数据库进行可视化:

    在这里插入图片描述

    使用示例

    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    
    app = Flask(__name__)
    
    
    class Config(object):
        """配置参数"""
        # sqlalchemy的配置参数
        SQLALCHEMY_DATABASE_URI = "mysql://root:你的密码@127.0.0.1:3306/zstar"
    
        # 设置sqlalchemy自动更跟踪数据库
        SQLALCHEMY_TRACK_MODIFICATIONS = True
    
        # 查询时会显示原始SQL语句
        app.config['SQLALCHEMY_ECHO'] = True
    
    
    # 连接数据库
    app.config.from_object(Config)
    
    # 创建数据库aqlalchemy工具对象
    db = SQLAlchemy(app)
    
    
    class Role(db.Model):
        # 定义表名
        __tablename__ = 'roles'
        # 定义列对象
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(32), unique=True)
        user = db.relationship('User', backref='role')
    
    
    class User(db.Model):
        __tablename__ = 'users'
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(32), unique=True, index=True)
        email = db.Column(db.String(32), unique=True)
        password = db.Column(db.String(32))
        role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    
    
    @app.route("/")
        # 第一种查询方式
        from sqlalchemy import text
        sql = text("select * from roles")
        result = db.engine.execute(sql)
        for row in result:
            print(row)
        # 第二种查询方式
        # print(Role.query.all())
        # print(Role.query.filter_by(id=2).first())
    
    @app.route("/create")
    def create():
        role1 = Role(name="admin")
        # session记录对象任务
        db.session.add(role1)
        # 提交任务到数据库中
        db.session.commit()
        return "The Role is created"
    
    # 创建表:
    # db.create_all()
    
    # 删除表
    # db.drop_all()
    
    
    if __name__ == '__main__':
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    本例中,首先需要手动创建数据库zstar,然后配置数据库连接ip和账号密码mysql://root:你的密码@127.0.0.1:3306/zstar,之后使用db.create_all()会创建前面定义出的数据表,同理db.drop_all()会删除前面定义出的数据表。这两句实测必须放在if __name__ == '__main__':外面,否则不会被运行,未知具体原因。

    本例中,我定义了两个接口,第一个根目录接口,分别尝试了通过sql来从直接查询和调用对象进行查询的两种查询方式,第二个/create接口,实现了向数据表Role中插入一个名称为admin的用户数据。

  • 相关阅读:
    Redis
    XStream常用注解学习
    18-数据结构-查找-B树和B+树
    asp.net core 如何统一json序列化格式
    【数组】用户分组 哈希表
    vue基础知识八:为什么data属性是一个函数而不是一个对象?
    微信公众号根据关键词取文章列表 API
    40.Java之Class、Type详谈
    UE4 C++ ActionRoguelike开发记录
    基于PHP+MySQL的服装购物商城系统#毕业设计
  • 原文地址:https://blog.csdn.net/qq1198768105/article/details/126015400