Web开发Flask框架基础知识

Posted zstar-_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

我安装的版本是Flask 2.1.3

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

pip freeze >requirements.txt

将需要的环境一起安装:

pip install -r requirements.txt

基本框架

在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()

路由请求方式限定

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

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

路由传递参数

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

@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

from flask import Flask, render_template

在templates文件夹下新建index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
测试Jinja2
</body>
</html>

进行调用

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

注释

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

变量/控制语句

在路由函数里,可以自定义变量,然后在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)

num_list对应html文件中的变量。

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

<body>
% for num in num_list %
     num 
% endfor %
</body>

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

输出效果:

过滤器

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

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

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

输出:

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

更多过滤器总结:

字符串操作

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

列表操作

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

语句块过滤

% filter upper %
    一大堆文字
% endfilter %

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>

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()

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

WTF表单方式

html

<!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

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安装

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服务

# 停止mysql服务
net stop mysql57 
# 启动mysql服务
net start mysql57

安装好之后,可以通过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()

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

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

以上是关于Web开发Flask框架基础知识的主要内容,如果未能解决你的问题,请参考以下文章

学习参考《Flask Web开发:基于Python的Web应用开发实战(第2版)》中文PDF+源代码

今晚九点|Flask 基础与 Web 开发实战

Flask框架怎么样,比起Web.py都有哪些不同

python flask框架怎么设置端口

python中flask框架 怎么选择文件

深入浅出Flask(10): H-ui前端框架入门之资源定位