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

2022-09-19 15:37:49 浏览数 (1)

本篇主要是黑马程序员的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安装

代码语言:javascript复制
pip install flask

我安装的版本是Flask 2.1.3

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

代码语言:javascript复制
pip freeze >requirements.txt

将需要的环境一起安装:

代码语言:javascript复制
pip install -r requirements.txt

基本框架

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

相关注释如下:

代码语言:javascript复制
from flask import Flask

# 指向程序所在的模块
app = Flask(__name__)


# 将路由映射到视图函数index
@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    # 启动WEB服务器
    app.run()

路由请求方式限定

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

代码语言:javascript复制
@app.route('/', methods=['GET', 'POST'])
def hello_world():
    return 'Hello World!'

路由传递参数

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

代码语言:javascript复制
@app.route('/orders/<int:order_id>')
def order(order_id):
    print(type(order_id))  # 类型为int
    return 'this is order %d' % order_id

Jinja2模板引擎

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

简单使用

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

先导入render_template

代码语言:javascript复制
from flask import Flask, render_template

在templates文件夹下新建index.html

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
测试Jinja2
</body>
</html>

进行调用

代码语言:javascript复制
@app.route('/', methods=['GET', 'POST'])
def index():
    return render_template('index.html')

注释

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

变量/控制语句

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

代码语言:javascript复制
@app.route('/', methods=['GET', 'POST'])
def index():
    my_list = [1, 2, 3, 4, 5]
    return render_template('index.html', num_list=my_list)

num_list对应html文件中的变量。

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

代码语言:javascript复制
<body>
{% for num in num_list %}
    {{ num }}
{% endfor %}
</body>

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

输出效果:

过滤器

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

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

代码语言:javascript复制
<body>
{#字符串转小写#}
<p>{{ 'HELLO' | lower }}</p>
{#获取列表长度#}
<p>{{ [1,2,3,4,5,6] | length }}</p>
</body>

输出:

注:使用连续的|可以同时使用多个过滤器

更多过滤器总结:

字符串操作

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

列表操作

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

语句块过滤

代码语言:javascript复制
{% filter upper %}
    一大堆文字
{% endfilter %}

Flask-WTF表单

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

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

普通方式

html

代码语言:javascript复制
<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>

app.py

代码语言:javascript复制
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()

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

WTF表单方式

html

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</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>

app.py

代码语言:javascript复制
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()

代码说明: 使用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安装

代码语言:javascript复制
pip install flask-sqlalchemy
pip install mysqlclient

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

安装mysql

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

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

代码语言:javascript复制
# 停止mysql服务
net stop mysql57 
# 启动mysql服务
net start mysql57

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

使用示例

代码语言:javascript复制
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()

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

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

0 人点赞