1、flask介绍
Flask是一个基于Python实现的web开发的’微’框架
flask流行的主要原因:
1 | a)有非常齐全的官方文档,上手非常方便 |
安装flask
虚拟环境搭建
1 | pip instatll virtualenv |
安装
1 | pip install flask |
基于flask的最小的应用
创建hello.py文件
1 | from flask import Flask |
运行:python hello.py
初始化
1 | from flask import Flask |
Flask类构造函数唯一需要的参数就是应用程序的主模块或包。对于大多数应用程序,Python的name变量就是那个正确的、你需要传递的值。Flask使用这个参数来确定应用程序的根目录,这样以后可以相对这个路径来找到资源文件。
路由
1 |
客户端例如web浏览器发送 请求 给web服务,进而将它们发送给Flask应用程序实例。应用程序实例需要知道对于各个URL请求需要运行哪些代码,所以它给Python函数建立了一个URLs映射。这些在URL和函数之间建立联系的操作被称之为 路由 。
在Flask应程序中定义路由的最便捷的方式是通过显示定义在应用程序实例之上的app.route装饰器,注册被装饰的函数来作为一个 路由。
视图函数
在上一个示例给应用程序的根URL注册gello_world()函数作为事件的处理程序。如果这个应用程序被部署在服务器上并绑定了 www.example.com 域名,然后在你的浏览器地址栏中输入 http://www.example.com 将触发gello_world()来运行服务。客户端接收到的这个函数的返回值被称为 响应 。如果客户端是web浏览器,响应则是显示给用户的文档。
类似于gello_world()的函数被称作 视图函数 。
动态名称组件路由
你的Facebook个人信息页的URL是 http://www.facebook.com/ ,所以你的用户名是它的一部分。Flask在路由装饰器中使用特殊的语法支持这些类型的URLs。下面的示例定义了一个拥有动态名称组件的路由:
1 |
|
用尖括号括起来的部分是动态的部分,所以任何URLs匹配到静态部分都将映射到这个路由。当视图函数被调用,Flask发送动态组件作为一个参数。在前面的示例的视图函数中,这个参数是用于生成一个个性的问候作为响应。
在路由中动态组件默认为字符串,但是可以定义为其他类型。例如,路由/user/int:id只匹配有一个整数在id动态段的URLs。Flask路由支持int、float
如下:
1 |
|
服务启动
1 | if __name__ == '__main__': |
注意: name == ‘main‘在此处使用是用于确保web服务已经启动当脚本被立即执行。当脚本被另一个脚本导入,它被看做父脚本将启动不同的服务,所以app.run()调用会被跳过。
一旦服务启动,它将进入循环等待请求并为之服务。这个循环持续到应用程序停止,例如通过按下Ctrl-C。
有几个选项参数可以给app.run()配置web服务的操作模式。在开发期间,可以很方便的开启debug模式,将激活 debugger 和 reloader 。这样做是通过传递debug为True来实现的。
run()中参数有如下:
1 | debug 是否开启调试模式,开启后修改python的代码会自动重启 |
修改启动方式
修改启动方式,使用命令行参数启动服务
安装插件
1 | pip install flask-script |
调整代码 manager = Manager(app=‘自定义的flask对象’)
启动的地方 manager.run()
启动命令
1 | python hellow.py runserver -h 地址 -p 端口 -d -r |
其中:-h表示地址。-p表示端口。-d表示debug模式。-r表示自动重启
route规则
规则
写法:converter:variable_name
converter类型:
1 | string 字符串 |
例子:
1 | @app.route('/helloint/<int:id>/') |
实现对应的视图函数:
1 |
|
methods请求方法
常用的请求类型有如下几种
1 | GET : 获取 |
定义url的请求类型:
1 | @blue.route('/getrequest/', methods=['GET', 'POST']) |
2、蓝图
什么是蓝图
在Flask项目中可以用Blueprint(蓝图)实现模块化的应用,使用蓝图可以让应用层次更清晰,开发者更容易去维护和开发项目。蓝图将作用于相同的URL前缀的请求地址,将具有相同前缀的请求都放在一个模块中,这样查找问题,一看路由就很快的可以找到对应的视图,并解决问题了。
使用蓝图
安装
1 | pip install flask_blueprint |
实例化蓝图应用
1 | blue = Blueprint('first',__name__) |
注意:Blueprint中传入了两个参数,第一个是蓝图的名称,第二个是蓝图所在的包或模块,name代表当前模块名或者包名
注册
1 | app = Flask(__name__) |
注意:第一个参数即我们定义初始化定义的蓝图对象,第二个参数url_prefix表示该蓝图下,所有的url请求必须以/user开始。这样对一个模块的url可以很好的进行统一管理
使用蓝图
修改视图上的装饰器,修改为@blue.router(‘/’)
1 |
|
注意:该方法对应的url为127.0.0.1:5000/user/
url_for反向解析
语法:
1 | url_for('蓝图中定义的第一个参数.函数名', 参数名=value) |
定义跳转:
1 | from flask import url_for, redirect |
3、访问请求数据
请求request
服务端在接收到客户端的请求后,会自动创建Request对象
由Flask框架创建,Requesy对象不可修改
属性:
1 | url:完整的请求地址 |
args—>GET请求参数包装
a)args是get请求参数的包装,args是一个ImmutableMultiDict对象,类字典结构对象
b)数据存储也是key-value
form—>POST请求参数包装
a)form是post请求参数的包装,args是一个ImmutableMultiDict对象,类字典结构对象
b)数据存储也是key-value
重点:ImmutableMultiDict是类似字典的数据结构,但是与字典的区别是,可以存在相同的键。在ImmutableMultiDict中获取数据的方式,dict[‘key’]或者dict.get(‘key’)或者dict.getlist(‘key’)
响应Response
Response是由开发者自己创建的
创建方法:
1 | from flask import make_response |
状态码:
格式:make_reponse(data,code),其中data是返回的数据内容,code是状态码
1 | a)直接将内容当做make_response的第一个参数,第二个参数直接写返回的状态码 |
例子1:
定义一个获取GET请求的request的方法,并将返回成功的请求的状态码修改为200
1 |
|
例子2:
返回response响应,并添加返回结果的状态码200
1 |
|
重定向/反向解析
1 | url_for('蓝图定义的名称.方法名') |
例子1:
定义跳转方法,跳转到get_response的方法上
1 |
|
例子2:
使用url_for反向解析
1 | from flask import redirect, url_for |
终止/异常捕获
自动抛出异常:abort(状态码)
捕获异常处理:errorhandler(状态码),定义的函数中要包含一个参数,用于接收异常信息
定义终止程序
1 |
|
捕获定义的异常
1 |
|
4、session与cookie
前言
访问者的标识问题服务器需要识别来自同一访问者的请求。这主要是通过浏览器的cookie实现的。 访问者在第一次访问服务器时,服务器在其cookie中设置一个唯一的ID号——会话ID(session)。 这样,访问者后续对服务器的访问头中将自动包含该信息,服务器通过这个ID号,即可区 隔不同的访问者。
Cookie
概念:
1 | a)客户端会话技术,浏览器的会话技术 |
创建:
1 | Cookie是通过服务器创建的Response来创建的 |
获取:
1 | 在每次请求中,url都会向服务器传递Request,在request中可以获取到cookie的信息 |
例子1,设置cookie:
1 | import datetime |
例子2,删除cookie中的值
1 | @blue.route('/setcookie/') |
例子3,获取cookie中的值
1 | @blue.route('/getcookie/') |
Session
flask-session是flask框架的session组件
该组件则将支持session保存到多个地方
如:
1 | redis:保存数据的一种工具,五大类型。非关系型数据库 |
安装
1 | pip install flask-session |
如果指定存session的类型为redis的话,需要安装redis
1 | pip install redis |
语法
设置session:
1 | session['key'] = value |
读取session:
1 | result = session['key'] :如果内容不存在,将会报异常 |
删除session:
1 | session.pop('key') |
清空session中所有数据:
1 | session.clear |
使用
我们在初始化文件中创建一个方法,通过调用该方法来获取到Flask的app对象
1 | def create_app(): |
案例
定义一个登陆的方法,post请求获取到username,直接写入到redis中,并且在页面中展示出redis中的username
a)需要先启动redis,开启redis-server,使用redis-cli进入客户端
b)定义方法
1 | @blue.route('/login/', methods=['GET', 'POST']) |
c)定义模板
1 | <body> |
d)redis中数据

注意:我们在定义app.config的时候指定了SESSION_KEY_PREFIX为flask,表示存在session中的key都会加一个前缀名flask
e) cookie和session的联系

访问者在第一次访问服务器时,服务器在其cookie中设置一个唯一的ID号——会话ID(session)。 这样,访问者后续对服务器的访问头中将自动包含该信息,服务器通过这个ID号,即可区 隔不同的访问者。然后根据不同的访问者来获取其中保存的value值信息。
4、模板
jinja2
Flask中使用jinja2模板引擎
jinja2是由Flask作者开发,模仿Django的模板引擎
优点:
1 | 速度快,被广泛使用 |
模板语法
模板语法主要分为两种:变量和标签
模板中的变量:
1 | 模板中的变量:{{ var }} |
1 | 视图传递给模板的数据 |
模板中的标签:
1 | 模板中的标签:{% tag %} |
1 | 控制逻辑 |
结构标签:
block
1 | {% block xxx %} |
extends
1 | {% extends ‘xxx.html’ %} |
挖坑继承体现的化整为零的操作
macro
1 | {% macro hello(name) %} |
宏定义可导入
1 | {% from 'xxx' import xxx %} |
例子1:
在index.html中定义macro标签,定义一个方法,然后去调用方法,结果是展示商品的id和商品名称
1 | {% macro show_goods(id, name) %} |
例子2:
在index.html页面中定义一个say()方法,然后解析该方法:
1 | {% macro say() %} |
例子3:
定义一个function.html中定义一个方法:
1 | {% macro create_user(name) %} |
在index.html中引入function.html中定义的方法
1 | {% from 'functions.html' import create_user %} |
循环
1 | {% for item in cols %} |
也可以获取循环信息loop
1 | loop.first |
例子:
在视图中定义一个视图函数:
1 |
|
(该视图函数,在下面讲解的过滤器中任然使用其返回的content_h2等参数)
首先: 在页面中进行解析scores的列表。题目要求:第一个成绩展示为红色,最后一个成绩展示为绿色,其他的不变
1 | <ul> |
过滤器
语法:
1 | {{ 变量|过滤器|过滤器... }} |
capitalize 单词首字母大写
lower 单词变为小写
upper 单词变为大写
title
trim 去掉字符串的前后的空格
reverse 单词反转
format
striptags 渲染之前,将值中标签去掉
safe 讲样式渲染到页面中
default
last 最后一个字母
first
length
sum
sort
例子:
1 | <ul> |
定义模板
定义基础模板base.html
1 | <!DOCTYPE html> |
定义基础模板base_main.html
1 | {% extends 'base.html' %} |
静态文件信息配置
django:
第一种方式:
1 | {% load static %} |
第二种方式:
1 | <link rel="stylesheet" href="/static/css/index.css"> |
flask:
第一种方式:
1 | <link rel="stylesheet" href="/static/css/index.css"> |
第二种方式:
1 | <link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}"> |
5、模型
Flask模型
Flask默认并没有提供任何数据库操作的API
我们可以选择任何适合自己项目的数据库来使用
Flask中可以自己的选择数据,用原生语句实现功能,也可以选择ORM(SQLAlchemy,MongoEngine)
SQLAlchemy是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy提供了高层ORM,也提供了使用数据库原生SQL的低层功能。
ORM:
1 | 将对对象的操作转换为原生SQL |
针对于Flask的支持,官网地址
1 | pip install flask-sqlalchemy |
安装驱动
1 | pip install pymysql |
定义模型
使用SQLALchemy的对象去创建字段
其中tablename指定创建的数据库的名称
1 | 创建models.py文件,其中定义模型 |
其中:
Integer表示创建的s_id字段的类型为整形,
primary_key表示是否为主键
String表示该字段为字符串
unique表示该字段唯一
default表示默认值
autoincrement表示是否自增
创建数据表
在视图函数中我们引入models.py中定义的db
1 | from App.models import db |
其中: db.create_all()表示创建定义模型中对应到数据库中的表
db.drop_all()表示删除数据库中的所有的表
初始化SQLALchemy
在定义的init.py文件中使用SQLALchemy去整合一个或多个Flask的应用
有两种方式:
1 | 第一种: |
配置数据库的访问地址
数据库连接的格式:
1 | dialect+driver://username:password@host:port/database |
例子: 访问mysql数据库,驱动为pymysql,用户为root,密码为123456,数据库的地址为本地,端口为3306,数据库名称HelloFlask
设置如下: “mysql+pymysql://root:123456@localhost:3306/HelloFlask”
在初始化init.py文件中如下配置:
1 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False |
对学生数据进行CRUD操作
语法:
1 | 类名.query.xxx |
获取查询集:
1 | all() |
数据操作:
1 | 在事务中处理,数据插入 |
想学生表中添加数据
1 | @blue.route('/createstu/') |
提交事务,使用commit提交我们的添加数据的操作
获取所有学生信息
将学生的全部信息获取到,并且返回给页面,在页面中使用for循环去解析即可
1 | @blue.route("/getstudents/") |
获取s_id=1的学生的信息
写法1:
1 | students = Student.query.filter(Student.s_id==1) |
写法2:
1 | students = Student.query.filter_by(s_id=2) |
注意:filter中可以接多个过滤条件
写法3:
1 | sql = 'select * from student where s_id=1' |
修改学生的信息
写法1:
1 | students = Student.query.filter_by(s_id=3).first() |
写法2:
1 | Student.query.filter_by(s_id=3).update({'s_name':'娃哈哈'}) |
删除一个学生的信息
写法1:
1 | students = Student.query.filter_by(s_id=2).first() |
写法2:
1 | students = Student.query.filter_by(s_id=1).all() |
注意:filter_by后的结果是一个list的结果集
重点注意:在增删改中如果不commit的话,数据库中的数据并不会更新,只会修改本地缓存中的数据,所以一定需要db.session.commit()
6、模型-一对多
深入数据库增删改查
定义模型,并定义初始化的函数:
1 | class Student(db.Model): |
增—批量增加
第一种方式:
1 | @blue.route('/createstus/') |
注:在创建单条数据的时候使用db.session.add(),在创建多条数据的时候使用db.session.add_all()
第二种方式:
1 | @blue.route('/createstus/') |
查—使用运算符
获取查询集
1 | filter(类名.属性名.运算符(‘xxx’)) |
运算符:
1 | contains: 包含 |
筛选:
1 | offset() |
逻辑运算:
1 | 与 |
例子1:
查询学生的id为3,4,5,6,16的的学生信息,使用in_逻辑运算
1
2
3
4
5
def get_stu_by_ids():
students = Student.query.filter(Student.s_id.in_([3,4,5,6,16]))
return render_template('StudentList.html', students=students)查询学生的年龄小于18岁的学生的信息
1
Student.query.filter(Student.s_age < 18)
查询学生的年龄小于18岁的学生的信息,lt小于
1
students = Student.query.filter(Student.s_age.__lt__(15))
查询学生的年龄小于等于18岁的学生的信息,le小于等于
1
students = Student.query.filter(Student.s_age.__le__(15))
查询学生的姓名以什么开始或者以什么结尾的学生的信息startswith和endswith
1
2students = Student.query.filter(Student.s_name.startswith('张'))
students = Student.query.filter(Student.s_name.endswith('2'))查询id=4的学生的信息
1
2Student.query.get(4)
获取的结果是学生的对象模糊搜索like
1
2
3
4%:代表一个或者多个
_:代表一个
Student.query.filter(Student.s_name.like('%张%'))分页,查询第二页的数据4条
1
2第一个参数是那一页,第二个参数是一页的条数,第三个参数是是否输出错误信息
students = Student.query.paginate(2, 4, False).items
例子2:
跳过offset几个信息,截取limit结果的几个值
1 | # 按照id降序排列 |
例子3:
查询
from sqlalchemy import and_, or_, not_
查询多个条件
stus = Student.query.filter(Student.s_age==18, Student.s_name==’雅典娜’)
and_ 并且条件
stus = Student.query.filter(and_(Student.s_age==18, Student.s_name==’雅典娜’))
or_ 或者条件
stus = Student.query.filter(or_(Student.s_age==18, Student.s_name==’火神’))
not_ 非
stus = Student.query.filter(not_(Student.s_age==18), Student.s_name==’火神’)
例子4:
分页:

后端数据处理:
1 | # 查询第几页的数据 |
前端数据展示:
1 | <h2>学生信息</h2> |
关联关系
一对多建立模型
学生模型:
1 | class Student(db.Model): |
班级模型:
1 | class Grade(db.Model): |
官网解释有如下几个lazy的参数:
lazy 决定了 SQLAlchemy 什么时候从数据库中加载数据:,有如下四个值:
1 | select/True: (which is the default) means that SQLAlchemy will load the data as necessary in one go using a standard select statement. |
1 | select就是访问到属性的时候,就会全部加载该属性的数据。 |
通过班级查询学生信息
1
2
3
4
5
6
7
8
9
10
11@grade.route('/selectstubygrade/<int:id>/')
def select_stu_by_grade(id):
grade = Grade.query.get(id)
# 通过班级对象.定义的relationship变量去获取学生的信息
stus = grade.students
return render_template('grade_student.html',
stus=stus,
grade=grade
)通过学生信息查询班级信息
1
2
3
4
5
6
7
8
9
10
11@stu.route('/selectgradebystu/<int:id>/')
def select_grade_by_stu(id):
stu = Student.query.get(id)
# 通过学生对象.定义的backref参数去获取班级的信息
grade = stu.stu
return render_template('student_grade.html',
grade=grade,
stu=stu)
注意:表的外键由db.ForeignKey指定,传入的参数是表的字段。db.relations它声明的属性不作为表字段,第一个参数是关联类的名字,backref是一个反向身份的代理,相当于在Student类中添加了stu的属性。例如,有Grade实例dept和Student实例stu。dept.students.count()将会返回学院学生人数;stu.stu.first()将会返回学生的学院信息的Grade类实例。一般来讲db.relationship()会放在一这一边。
数据库迁移
在django中继承了makemigrations,可以通过migrate操作去更新数据库,修改我们定义的models,然后在将模型映射到数据库中。
在flask中也有migrate操作,它能跟踪模型的变化,并将变化映射到数据库中
安装migrate
1 | pip install flask-migrate |
配置使用migrate
初始化,使用app和db进行migrate对象的初始化
1 | from flask_migrate import Migrate |
安装了flask-script的话,可以在Manager()对象上添加迁移指令
1 | from flask_migrate import Migrate, MigrateCommand |
操作:
1 | python manage.py db init 初始化出migrations的文件,只调用一次 |
7、模型-多对多
关联关系—-多对多
定义模型:
引入SLALchemy
1 | from flask_sqlalchemy import SQLAlchemy |
创建中间表
1 | sc = db.Table('sc', |
创建学生类Student
1 | class Student(db.Model): |
创建课程表的模型,Course类
1 | class Course(db.Model): |
sc表由db.Table声明,我们不需要关心这张表,因为这张表将会由SQLAlchemy接管,它唯一的作用是作为students表和courses表关联表,所以必须在db.relationship()中指出sencondary关联表参数。lazy是指查询时的惰性求值的方式,这里有详细的参数说明,而db.backref是声明反向身份代理,其中的lazy参数是指明反向查询的惰性求值方式.
添加学生和课程之间的关系
通过页面中传递学生的id和课程的id,分别获取学生的对象和课程的对象,在使用关联关系append去添加学生对象,并且add以后再commit后,就可以在中间表sc中查看到新增的关联关系了。
1 | userid = request.form.get('userid') |
删除学生和课程之间的关系
通过页面获取传递的学生的id和课程的id,分别获取学生对象和课程对象,在使用关联关系remove去删除学生对象,并commit将事务提交到数据库中
1 | stu = Student.query.get(s_id) |
通过课程查询学生的信息
以下定义在课程course的模型中,所以通过课程查询学生的信息,语法为课程的对象.studengs。如果知道学生的信息反过来找课程的信息,则使用backref的反向关联去查询,语语法为学生的对象.cou(反向)
students = db.relationship(‘Student’,secondary=sc,backref=’cou’)
1 | cou = Course.query.get(2) |
通过学生去查询课程的信息
1 | stu = Student.query.get(id) |
8、插件
开发,页面调试工具debugtoolbar
1.1 安装
1 | pip install flask-debugtoolbar |
1.2 配置
1 | from flask import Flask |
2. restful
Flask-RESTful 提供的最主要的基础就是资源(resources)。资源(Resources)是构建在 Flask 可拔插视图 之上,只要在你的资源(resource)上定义方法就能够容易地访问多个 HTTP 方法
官网上描述了一个最简单的restful风格的api,如下:
1 | from flask import Flask |
2.1 安装
1 | pip install flask_restful |
2.2 配置
在create_app()获取Flask(name)对象中,设置如下配置
1 | from flask_restful import Api |
在views中需要引入配置的api还有Resource
1 | # 导入包和restful中的Api对象 |
2.3 端点(Endpoints)
在一个 API 中,你的资源可以通过多个 URLs 访问。你可以把多个 URLs 传给 Api 对象的 Api.add_resource() 方法。每一个 URL 都能访问到你的 Resource
如:
1 | api.add_resource(CreateCourse, '/api/course/<int:id>/', '/api/course/') |
2.4 返回响应
Flask-RESTful 支持视图方法多种类型的返回值。同 Flask 一样,你可以返回任一迭代器,它将会被转换成一个包含原始 Flask 响应对象的响应。Flask-RESTful 也支持使用多个返回值来设置响应代码和响应头
如:
1 | def get(self, id): |