1 Flask
1.1 Flask初识
Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架。
Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login,数据库Flask-SQLAlchemy),都需要用第三方的扩展来实现。比如可以用 Flask 扩展加入ORM、窗体验证工具,文件上传、身份验证等。Flask 没有默认使用的数据库,你可以选择 MySQL,也可以用 NoSQL
Flask核心 Werkzeug 和Jinja2
1.Werkzeug实现路由、调试和Web服务器网关接口
Werkzeug是一个遵循WSGI协议的python函数库
1.1其内部实现了很多Web框架底层的东西,比如request和response对象;
1.2与WSGI规范的兼容;支持Unicode;
1.3支持基本的会话管理和签名Cookie;
1.4集成URL请求路由等
Werkzeug库的routing模块负责实现URL解析。不同的URL对应不同的视图函数,routing模块会对请求信息的URL进行解析,匹配到URL对应的视图函数,以此生成一个响应信息
routing模块内部
Rule类(用来构造不同的URL模式的对象)
Map类(存储所有的URL规则)
BaseConverter的子类(负责定义匹配规则)
MapAdapter类(负责具体URL匹配的工作)
2.Jinja2实现了模板 支持相应的Jinjia2模板语法
2.1变量{{ data }}
2.2控制语句{% if 1 %} {%else %} {%endif %}
2.3循环语句{% for i in range(4) %} {% endfor %}
Flask常用扩展包:
Flask-SQLalchemy:操作数据库;
Flask-script:插入脚本;
Flask-migrate:管理迁移数据库;
Flask-Session:Session存储方式指定;
Flask-WTF:表单;
Flask-Mail:邮件;
Flask-Bable:提供国际化和本地化支持,翻译;
Flask-Login:认证用户状态;
Flask-OpenID:认证;
Flask-RESTful:开发REST API的工具;
Flask-Bootstrap:集成前端Twitter Bootstrap框架;
Flask-Moment:本地化日期和时间;
Flask-Admin:简单而可扩展的管理接口的框架
2 Flask环境构建
# pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple
2.1 Flask实例
from flask import Flask
# 创建flask对象
app = Flask(__name__)
#路由匹配对应的视图函数: app.add_url_rule('/', test)
@app.route("/")
def test():
return "<h1>flask 测试</h1>"
if __name__ == '__main__':
# 运行flask
app.run(debug=True)
#terminal
#app.run(host, port, debug, options)
#默认访问http://127.0.0.1:5000/
#可修改host port:app.run(host="localhost", port=9999)
#debug=True 程序进行修改自动调试重启
#app=Flask(__name__, template_folder="", static_folder="", static_url_path="")
#__name__:此模块所在的目录为工作目录 静态文件等都从这个目录找
#template_folder:设置模板文件加载目录(默认templates)
#static_folder:设置静态资源加载目录(默认static)
#static_url_path:静态资源访问url
3 路由
# 查看flask应用路由表
print(app.url_map)
#/:映射test函数
#/static/<filename>/:静态资源访问路径
#out:
#Map([<Rule '/' (HEAD, GET, OPTIONS) -> test>,<Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])
# 小结:
# 路由用于指定请求url时对应的处理函数
#@app.route(rule, option)
#rule:路由url 携带参数使用<参数>, 类型限制是<int:参数>;
#option:转发给rule的参数列表
#url_for('视图函数名')函数 返回特定url
4 视图
from flask import Flask, render_template
# 创建flask对象
app = Flask(__name__)
@app.route("/")
def index():
# return "flask 测试"
# 返回指定页面
return render_template('home.html')
@app.route("/test/<num>")
# 视图函数处理url携带参数情况
def test1(num):
return "flask请求携带参数:" + num
if __name__ == '__main__':
# 运行flask
app.run(debug=True)
# 视图函数(装饰器app.route修饰的函数)
# 1.处理请求url对应的逻辑
# 2.返回页面数据
# 3.传递数据到前端模板
5 模板
5.1 默认模板引擎jinja2
Jinja2:是 Python 下一个被广泛应用的模板引擎,是由Python实现的模板语言,他的设计思想来源于 Django 的模板引擎,并扩展了其语法和一系列强大的功能,其是Flask内置的模板引擎
模板语言:是一种被设计来自动生成文档的简单文本格式
在模板语言中,一般都会把一些变量传给模板,替换模板的特定位置上预先定义好的占位变量名
Flask提供的 render_template 函数封装了该模板引擎 render_template 函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板中变量对应的真实值。
5.2 jinja2语法
1.变量
{{ name }}
2.控制语句
{% if 1 %}
{% else %}
{% endif %}
3.循环
{% for 1 %}
{% endfor %}
4.注释
{# 这里是注释部分 #}
5.1 默认过滤器
safe: 渲染时值不转义直接输出
capitialize: 把值的首字母转换成大写,其他子母转换为小写
lower: 把值转换成小写形式
upper: 把值转换成大写形式
title: 把值中每个单词的首字母都转换成大写
trim: 把值的首尾空格去掉
striptags: 渲染之前把值中所有的HTML标签都删掉
join: 拼接多个值为字符串
replace: 替换字符串的值
round: 默认对数字进行四舍五入,也可以用参数进行控制
int: 把值转换成整型
truncate: 字符串截断
format:格式化输出
first:取第一个元素
length:获取列表长度
sum:列表求和
sort:列表排序
{{ Flask | reverse | lower}} -> ksalf
{{ [1,2,3] | first}} -> 1
5.2 自定义过滤器
方式一:
def fn(li):
temp = li
li.reverse()
return li
app = Flask(__name__)
app.add_template_filter(fn, 'fn') # 函数名 过滤器名
方式二:
@app.template_filter('fn')
def fn(li):
temp = li
li.reverse()
return li
{{ [1,2,3] | fn}} -> [3,2,1]
6.宏(复用前端代码)
----a.html
{% macro input(name,value='', type='text') %}
<input name="{{name}}", value="{{value}}", type="{{type}}">
{% endmacro %}
内部使用
{{ input('aa', 'bb') }}
----b.html
外部使用
{% import 'a.html' as fn %}
{{fn.input('aa', 'bb')}}
7.模板继承(复用前端代码)
----c.html
{% block 自定义名 %}
<input type='text', name='xx', value='yy'>
{% endblock %}
----d.html
{% extends 'c.html' %}
继承c.html的前端代码
{% block 自定义名 %}
不同与c.html代码的部分
{% endblock %}
继承c.html的前端代码
8. include(直接将整个模板代码复制)
#----e.html
{% include 'c.html' ignore missing %} 参数ignore missing避免c.html找不到抛出异常
5.3 实例
#----templates/test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
{# 条件控制 #}
{% if num>2 %}
{# 变量替换 #}
<p>{{ name }}</p>
{% else %}
<p>num < 2 </p>
{% endif %}
{# 循环 #}
{% for i in range(5) %}
<p>flask test...</p>
{% endfor %}
{# 宏使用#}
{% macro input(name,value='', type='text') %}
<input name="{{name}}", value="{{value}}", type="{{type}}">
{% endmacro %}
{{ input('aa', 'bb') }}
</body>
#----app.py
from flask import Flask, render_template, url_for, redirect
# 创建flask对象
app = Flask(__name__)
@app.route("/test/<num>")
# 视图函数处理url携带参数情况
def test1(num):
name = "hello flask"
# redirect重定向跳转到指定页面
# url_for("视图函数"):url("/")
# return redirect(url_for("index"))
# with open("./test.html") as f:
# content = f.read()
# return content
return render_template('test.html', name=name, num=int(num))
if __name__ == '__main__':
# 运行flask
app.run(debug=True)
# 小结:
# 1.动态资源请求url通过匹配特定视图函数进行处理
# 2.静态资源(css,js)请求:/static/<filename>/ 默认放置在static目录下 配置完templates(html文件) 自动加载

6 数据库
6.1 sqlalchemy
$pip install sqlalchemy # orm操作
$pip install pymysql or pip install mysqlclient # 数据库链接
6.2 sqlalchemy 字段
sqlalchemy 字段类型
Integer 普通整数,一般是32位
SmallInteger 取值范围小的整数,一般是16位
BigInteger 不限制精度的整数
Float 浮点数
Numeric 普通整数,一般是32位
String 变长字符串
Text 变长字符串,对较长或不限长度的字符串做了优化
Unicode 变长Unicode字符串
UnicodeText 变长Unicode字符串,对较长或不限长度的字符串做了优化
Boolean 布尔值
Date 时间
Time 日期和时间
LargeBinary 二进制文件
sqlalchemy字段约束
autoincrement True自增长
primary_key True则为主键
unique True则代表字段值不可重复
index True代表该字段创建索引 提高查询速度
nullable True代表字段可以为空
default 字段默认值
comment 字段描述
sqlalchemy表与表之间关系约束
字段约束
backref= | back_populates= 在关系表(一对多 多对一)模型相关字段添加反向引用关联
ForeignKey() 声明关联的外键
secondary= 关联多对多关系模型 值为关联表名
模型类约束
relationship() 关联数据模型可直接通过属性获取对方对象(单独一个模型类对象参数为正向引用)
class A(base):
pass
class B(base):
b = relationship('A', backref='bb')
B.b获取A对象数据 A.bb获取B对象数据
relationship(lazy='') lazy属性(lazy 决定了 SQLAlchemy 什么时候从数据库中加载数据)
1.select(默认): 访问到属性的时候,就会全部加载该属性的数据[<User 1>, <User 3>]
2.joined: 对关联的两个表使用联接
3.dynamic: 在访问属性的时候,并没有在内存中加载数据,而是返回一个query对象 只作用于一对多 和多对多关系
6.3 sqlalchemy 增删改查
# sqlalchemy所有操作依附于会话对象session = sessionmaker(bind=engineer)()
# user为一个模型类实例对象 User为模型类
# 增
session.add(user) # 加一个
session.add_all([user1, user2]) # 加多个
session.commit()
# 删
session.delete(user)
session.commit()
# 改
session.query(User).filter(User.id=1).update({'name': 'aa'})
session.commit()
# 查
session.query(User).all() # 查所有
session.query(User).one() # 查一个
session.query(User).filter().all() # 附加条件查
filter(User.name.like("%a_")) # 模糊查询
filter(User.name=='aa', User.id=1) # 默认and条件查询
filter(and_(User.name=='aa', User.id=1)) # and多条件查询
filter(or_(User.name=='aa', user.id=1)) # or条件查询
filter(not_(User.name=='aa', user.id=1)) # not条件查询
session.query(User).order_by(-User.id).all() # 排序查(默认升序 -:降序)
# 最后关闭会话对象
session.close()
6.4 sqlalchemy 实例
from sqlalchemy import create_engine, Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, sessionmaker
# 前提:创建数据库create database flask_web charset=utf8;
# 链接数据库mysql
engineer = create_engine('mysql+pymysql://用户:密码@localhost:3306/flask_web')
# engineer = create_engine('mysql://root:xxx@localhost:3306/flask_web')
# engineer = create_engine('mysql+mysqldb://root:xxx@localhost:3306/flask_web')
# 生成sqlorm基类(自带orm实现方式)
base = declarative_base()
# 创建表模型类
class User(base):
__tablename__ = 'user' # 表名
# 表字段
id = Column(Integer, primary_key=True)
name = Column(String(30), nullable=False, comment="姓名")
password = Column(String(30), nullable=False)
email = Column(String(30), nullable=False)
job = Column(String(30), nullable=False)
addr = Column(String(100), nullable=False)
company = Column(String(50), nullable=False)
def __repr__(self):
return "name=%s\n password=%s \n email=%s \n job=%s \n addr=%s\n company=%s" % (self.name, self.password, self.email, self.job, self.addr, self.company)
# 创建完表模型类调用 用于创建数据表或删除数据表
def db_operator(num):
if num == 1:
# 创建所有表
base.metadata.create_all(engineer)
else:
# 删除所有表
base.metadata.drop_all(engineer)
# db_operator(1)
# 创建会话对象对数据库进行操作
# session = sessionmaker(bind=engineer)() # 通过sessionmaker()创建的会话对象可不再进行初始化配置
session = Session(bind=engineer) # 每次创建会话对象需要初始化配置(数据库连接)
# 添加
user = User(name='fsh',
password='666666',
email="3172013218@qq.com",
job='Python开发工程师',
addr="上海黄浦区",
company="实业互联网公司"
)
session.add(user)
session.commit() # 除了查询 其他操作均需要提交操作
session.close() # 关闭会话对象释放资源
# 修改
session.query(User).filter(User.name == 'fsh').update({'name': 'xyz'})
session.commit()
session.close()
# 查询
all = session.query(User).all()
print(all[0] if all else None)
# 删除
user = session.query(User).filter(User.name == 'xyz').one() # 查询删除的对象
session.delete(user)
session.commit()
session.close()
# 小结:
# 模型类中:__repr__ 用于调试打印对象输出需要的对象数据
# __str__:输出数据; __repr___:数据+类型(默认调用repr()函数)
6.5 sqlalchemy 多表关系
6.5.1 一对多
import datetime
from sqlalchemy import create_engine, Column, String, Integer, Text, DateTime, ForeignKey, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref, sessionmaker
# 链接数据库mysql
engineer = create_engine('mysql+pymysql://root:python@localhost:3306/flask_web')
# engineer = create_engine('mysql://root:python@localhost:3306/flask_web')
# engineer = create_engine('mysql+mysqldb://root:python@localhost:3306/flask_web')
# 生成sqlorm基类(自带orm实现方式)
base = declarative_base()
# 创建表
class User(base):
"""用户表"""
__tablename__ = 'user' # 表名
# 表字段
id = Column(Integer, primary_key=True)
name = Column(String(30), nullable=False)
password = Column(String(30), nullable=False)
email = Column(String(30), nullable=False)
job = Column(String(30), nullable=False)
addr = Column(String(100), nullable=False)
company = Column(String(50), nullable=False)
article = relationship('Article', backref='user')
def __repr__(self):
return "name=%s\n password=%s \n email=%s \n job=%s \n addr=%s\n company=%s" % (self.name, self.password, self.email, self.job, self.addr, self.company)
class Article(base):
"""文章表"""
__tablename__ = 'article'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50), nullable=False)
base_info = Column(Text, nullable=False)
read_num = Column(Integer, default=0)
comment_num = Column(Integer, default=0)
user_id = Column(Integer, ForeignKey('user.id'))
create_time = Column(DateTime, default=datetime.datetime.utcnow)
update_time = Column(DateTime(timezone=True), onupdate=func.now())
def __repr__(self):
return "title=%s" % self.title
# session会话对象对数据库操作
session = sessionmaker(bind=engineer)()
# 添加数据
user = User(name='fsh',
password='666666',
email="3172013220@qq.com",
job='Python开发工程师',
addr="上海黄浦区",
company="公司",
)
article = Article(title="python基础",
base_info="python xxx",
user=user)
session.add_all([user, article])
session.commit()
# 查询数据
print(session.query(User).first().article) # 获取用户所属文章
print(session.query(Article).first().user) # 获取文章所属用户
session.close()
# 小结:
# relationship()关联相互有关系的表
# 可以使用user表查询article表 不会在数据表添加字段article,只是建立关联
# 第一个参数为关联的模型类(表)(正向引用) 为user添加一个属性user.article 可获取作者所有文章;
# 第二个参数backref(反向引用)为article添加一个属性article.user可以获取文章所属作者
6.5.2 多对多
class Article_Tag(base):
__tablename__ = 'a_t'
id = Column(Integer, primary_key=True, autoincrement=True)
article_id = Column(Integer, ForeignKey('article.id'))
tag_id = Column(Integer, ForeignKey('tag.id'))
# 方式一(relationship关联)
# article = relationship('Article', backref='tag')
# tag = relationship('Tag', backref='article')
class Article(base):
"""文章表"""
__tablename__ = 'article'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50), nullable=False)
base_info = Column(Text, nullable=False)
read_num = Column(Integer, default=0)
comment_num = Column(Integer, default=0)
create_time = Column(DateTime, default=datetime.datetime.utcnow)
update_time = Column(DateTime(timezone=True), onupdate=func.now())
# 方式二
tag = relationship('Tag', secondary=Article_Tag.__table__, backref='article')
def __repr__(self):
return "title=%s" % self.title
class Tag(base):
"""标签表"""
__tablename__ = 'tag'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=True, comment="标签名")
def __repr__(self):
return "name=%s" % self.name
# 创建会话对象
session = Session(bind=engineer)
# 添加数据使用方式一
art = Article(title="Flask基础",
base_info="hello flask",
)
tag = Tag(name="flask")
a_t = Article_Tag(article=art,
tag=tag)
session.add_all([art, tag, a_t])
session.commit()
# 查询 使用方式二
print(session.query(Article).first().tag) # 获取文章所属标签
print(session.query(Tag).first().article) # 获取标签下所有文章
session.close()
6.5 flask_sqlalchemy
$pip install flask_sqlalchemy
6.6 flask_sqlalchemy 实例
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__) # 创建flask应用
# flask配置
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:python@localhost:3306/flask_web"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 自动追踪数据库更新
app.config['SQLALCHEMY_ECHO'] = False # 查询显示原始sql语句
# sqlalchmey关联flask应用
db = SQLAlchemy(app) # 创建sqlalchmey实例对象并关联flask
class User(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False)
class Cls(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
cls_name = db.Column(db.String(50), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship('User', backref='cls')
def db_init(num):
if num == 1:
db.create_all() # 创建数据表
else:
db.drop_all() # 删除数据表
# 创建数据表
db_init(1)
6.7 flask_sqlalchemy 增删改查
# 增
u1 = User(name='xyz')
u2 = User(name='xxx')
u3 = User(name='yyy')
u4 = User(name='zzz')
c1 = Cls(cls_name="计算机应用技术1班", user=u1)
c2 = Cls(cls_name="计算机应用技术2班", user=u2)
c3 = Cls(cls_name="计算机应用技术3班", user=u3)
c4 = Cls(cls_name="计算机应用技术4班", user=u4)
db.session.add_all([u1, u2, u3, u4, c1, c2, c3, c4])
db.session.commit()
# 改
db.session.query(User).filter_by(name='xyz').update({'name':'gg'})
db.session.commit()
# 删
db.session.query(Cls).filter_by(id=1).delete()
db.session.query(User).filter_by(id=1).delete()
db.session.commit()
# 查
User.query.all()
User.query.filter().one() # 没有 报错
User.query.filter().first() # 没有 None
# 条件查询
User.query.filter().first()
User.query.filter(User.id.__gt__(1)).all() # id>1
User.query.filter(User.id.__le__(3)).all() # id<=3
from sqlalchemy import and_, or_, not_
User.query.filter(and_(User.id==1, User.name=="xyz").first() # and
User.query.filter(or_(User.id==1, User.id==3)).all() # or
User.query.filter(not_(User.id==2)).all() # not
User.query.filter(User.id.in_([1, 3])).all() # 非连续
User.query.filter(User.id.between(1, 3)).all() # 连续
User.query.filter(User.name.like("%y%")).all() # 模糊
User.query.group_by(User.id).having(User.name=="xyz").all() # 分组 having对分组结果再过滤
User.query.order_by(-User.id).all() # 排序(默认升序 -:降序)
User.query.filter(User.id.__ge__(1)).offset(2).limit(1).all() # limit限制输出数量1 offset偏移2 从第三条数据开始输出
6.8 flask_sqlalchemy 与 sqlalchmey
# 模型类定义
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
app = Flask(__name__)
app.config[database_url]
db.init_app(app)
flask_sqlalchemy 使用db.Model
flask_sqlalchemy 表名默认为模型类小写
#---------------------------------------
from sqlalchemy.ext.declarative import declarative_base
base = declarative_base()
sqlalchemy 使用base
sqlalchemy 需要定义__tablename__ 声明表名
#---------------------------------------
# 字段
flask_sqlalchemy 使用db.Integer
sqlalchemy 使用 from sqlalchemy import Integer
# 会话对象
flask_sqlalchemy db.session 自动关闭
sqlalchemy session.close() 手动关闭
# 查询
flask_sqlalchemy 可使用User.query.all()
sqlalchemy 使用会话对象访问session.query(User).all()
6.9 数据库迁移
6.9.1 相关包安装
#(alembic:迁移框架) flask_migrate轻量级封装
$pip install flask-migrate # flask数据表迁移插件
$pip install flask-script # 扩展管理flask命令 使用命令方式操作flask相关应用
6.9.2 实例
#----test.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
#创建flask实例
app = Flask(__name__)
# flask配置
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:python@localhost:3306/flask_web"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 自动追踪数据库更新
app.config['SQLALCHEMY_ECHO'] = False # 查询显示原始sql语句
# sqlalchmey关联flask应用
db = SQLAlchemy(app)
# 模型类(可在其他目录 在其他目录切记数据库迁移需要先在其他模块有导入相关模型类操作 否则会导致迁移没有变化)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False)
class Cls(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
cls_name = db.Column(db.String(50), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship('User', backref='cls')
# 数据库迁移
manage = Manager(app) # 命令行管理工具关联flask
migrate = Migrate(app, db) # migrate关联flask 和 sqlalchemy对象
manage.add_command('db', MigrateCommand) # 添加命令db + 迁移命令
manage.run()
# terminal操作
$python test.py db init # 初始化迁移仓库 生成migratons文件夹 存放数据库的修改记录 相关的配置文件
$python test.py db migrate -m"描述信息" # 生成迁移脚本文件
$python test.py db upgrade # 迁移脚本映射到数据库 真正创建数据表
$python test.py db downgrade # 回撤 后面可加版本号
# 后续数据表修改 直接使用 1.python test.py db migrate 2.python test.py db upgrade

7 文档: