Flask高效数据库操作指南

Flask-SQLAlchemy 数据库操作

关于Flask数据库

Flask中没有指定使用的数据库,可以自由选择不管你是使用关系型数据库,还是非关系型数据库都可以,不像django提供了orm 数据库抽象层,可以直接采用对象的方式操作数据库。但是为了开发效率,在开发Flask项目中我们一般会选择 SQLALchemy 来操作数据库,类似于Django的ORM。SQLALchemy实际上是对数据库的抽象,让开发者不直接使用sql语句做开发,而是通过Python对象来操作数据库,在舍弃一些性能开销的同时,换来的是开发效率的较大提升。

SQLAlchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。为了简化配置和操作,我们使 Flask-SQLAlchemy,这个 Flask 扩展封装了 SQLAlchemy 框架。

安装 Flask-SQLAlchemy

复制代码
pip install Flask-SQLAlchemy

要连接mysql数据库还需要安装flask-mysqldb

复制代码
pip install flask-mysqldb

如果安装报下面错误

复制代码
Command "python setup.py egg_info" failed with error code 1

请先安装执行下面这条命令:(Linux)

复制代码
sudo apt-get install mysql-server libmysqld-dev

示例:

python 复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
​
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:xxxxxx@127.0.0.1/flask01'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True  # 追踪对象的修改并且发送信号
db = SQLAlchemy(app)
​
class User(db.Model):
    # SQLAlchemy 需要手动执行主键列,第一个参数是 字段类型,第二个参数是约束条件
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(20),unique=True)
​
if __name__ == '__main__':
    with app.app_context():  # 添加应用上下文
        # 创建所有表
        db.create_all()

1. 数据库连接配置

python 复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
​
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/py'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True  # 追踪对象的修改并且发送信号
db = SQLAlchemy(app)

配置键说明

配置键 说明
SQLALCHEMY_DATABASE_URI 设置连接数据库<br>格式:mysql://username:password@server/db
SQLALCHEMY_BINDS 一个映射绑定 (bind) 键到 SQLAlchemy 连接 URIs 的字典。更多的信息请参阅 绑定多个数据库。
SQLALCHEMY_ECHO 如果设置成 True,SQLAlchemy 将会记录所有 发送 标准输出(stderr)的语句,这对调试很有帮助。
SQLALCHEMY_RECORD_QUERIES 可以用于显式地禁用或者启用查询记录。查询记录 在调试或者测试模式下自动启用。更多信息请参阅 get_debug_queries()。
SQLALCHEMY_NATIVE_UNICODE 可以用于显式地禁用支持原生的 unicode。这是 某些数据库适配器必须的(像在 Ubuntu 某些版本上 的 PostgreSQL),当使用不合适的指定无编码的数 据库 默认值时。
SQLALCHEMY_POOL_SIZE 数据库连接池的大小、默认是数据库引擎的默认值 (通常是 5)。
SQLALCHEMY_POOL_TIMEOUT 指定数据库连接池的超时时间。默认是 10。
SQLALCHEMY_POOL_RECYCLE 自动回收连接的秒数。这对 MySQL 是必须的,默认 情况下 MySQL 会自动移除闲置 8 小时或者以上的连 接。需要注意的是如果使用 MySQL 的话,Flask-SQLAlchemy 会自动地设置这个值为 2 小时。
SQLALCHEMY_MAX_OVERFLOW 控制在连接池达到最大值后可以创建的连接数。当这 些额外的连接回收到连接池后将会被断开和抛弃。
SQLALCHEMY_TRACK_MODIFICATIONS 如果设置成 True (默认情况),Flask-SQLAlchemy 将 会追踪对象的修改并且发送信号。这需要额外的内 存,如果不必要的可以禁用它。
SQLALCHEMY_COMMIT_ON_TEARDOWN 每次请求结束后会自动提交数据库中的改动

数据库URI格式

数据库 URI格式
MySQL mysql://username:password@hostname/database
Postgres postgresql://username:password@hostname/database
SQLite (Unix) sqlite:////python/data/database
SQLite (Windows) sqlite:///c:/db/data/database
Oracle oracle://scott:tiger@127.0.1:1521/sidname

字段说明: username:登录数据库的用户名 password:登录数据库的密码 hostname:服务器主机 ip,可以是本地主机(localhost)也可以是远程服务器 database:表示要使用的数据库


2. 模型类定义

字段类型

类型名 Python中类型 说明
Integer int 普通整数,一般是32位
SmallInteger int 小整数
BigInteger int或long 大整数
Float float 浮点数
Numeric decimal.Decimal 普通整数,一般是32位
String str 变长字符串
Text str 变长字符串,对较长或不限长度的字符串做了优化
Unicode unicode 变长Unicode字符串
UnicodeText unicode 变长Unicode字符串,对较长或不限长度的字符串做了优化
Boolean bool 布尔值
Date datetime.date 时间
Time datetime.datetime 日期和时间
LargeBinary str 二进制文件

约束条件

约束 说明
primary_key 主键
unique 唯一约束,True不允许重复
index 索引,如果为True,为这列创建索引,提高查询效率
nullable 空值,如果为True,允许有空值,如果为False,不允许有空值
default 默认值

关系类型

关系 说明
One To Many(一对多) 表示一对多的关系时,在子表类中通过 foreign key (外键)引用父表类,在父表类中通过 relationship() 方法来引用了表的类
One To One(一对一) 一对一是两张表之间本质上的双向关系。只需要在一对多关系基础上的父表中使用 uselist=False 参数来表示
Many To Many(多对多) 多对多关系会在两个类之间增加一个关联的表,连个关系表中使用 relationship() 方法中通过 secondary 来引用关联表,关联表通过 MetaData 对象与声明基类关联,使用ForeignKey 连接接来定位到远程的表

3. 关系模型

一对多关系
python 复制代码
class Father(db.Model):
    """创建一个父表模型类"""
    # 表名
    __tablename__ = 'father'
    # id主键列,整数类型,自增
    id = db.Column(db.Integer, primary_key=True)
    # name,可变长字符串类型
    name = db.Column(db.String(20))
    # 关系字段,不是数据库中真实存在的字段,而是为了方便查询添加的属性
    son = db.relationship('Son', backref='father')
​
class Son(db.Model):
    """创建一个子表模型类"""
    # 表名
    __tablename__ = 'son'
    # id主键列,整数类型,自增
    id = db.Column(db.Integer, primary_key=True)
    # name,可变长字符串类型
    name = db.Column(db.String(20))
    # 外键,需要指定字段类型,以及关联那个表的那个字段
    father_id = db.Column(db.Integer, db.ForeignKey('father.id'))
一对一关系
python 复制代码
class Father(db.Model):
    """创建一个父类模型类"""
    # 表名
    __tablename__ = 'father'
    # id主键列,整数类型,自增
    id = db.Column(db.Integer, primary_key=True)
    # name,可变长字符串类型
    name = db.Column(db.String(20))
    # 关系字段,不是数据库中真实存在的字段,而是为了方便查询添加的属性
    son = db.relationship('Son', backref='father', uselist=False)
​
class Son(db.Model):
    """创建一个子表模型类"""
    # 表名
    __tablename__ = 'son'
    # id主键列,整数类型,自增
    id = db.Column(db.Integer, primary_key=True)
    # name,可变长字符串类型
    name = db.Column(db.String(20))
    # 外键,需要指定字段类型,以及关联那个表的那个字段
    father_id = db.Column(db.Integer, db.ForeignKey('father.id'))
多对多关系
python 复制代码
# 多对多关系中的两个表之间的一个关联表
association_table = db.Table('association', db.metadata,
    db.Column('author_id', db.Integer, db.ForeignKey('author.id')),
    db.Column('book_id', db.Integer, db.ForeignKey('book.id'))
)
​
class Author(db.Model):
    """创建作者模型类"""
    # 指定表名,如果没有指定将默认使用模型类的名称
    __tablename__ = 'author'
    # id 类型是整数 主键列
    id = db.Column(db.Integer, primary_key=True)
    # name 类型是可变长字符串,唯一
    name = db.Column(db.String(20), unique=True)
    # 关联中间表,不是数据库中真实存在的字段,而是为了方便查询添加的属性
    book = db.relationship('Book', back_populates='author',
                          secondary=association_table)
​
class Book(db.Model):
    """创建书模型类"""
    # 指定表名,如果不指定将使用模型类名称作为表名
    __tablename__ = 'book'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20))
    # 关联中间表,不是数据库中真实存在的字段,而是为了方便查询添加的属性
    author = db.relationship("Author", secondary=association_table,
                            back_populates="book")

4. 数据操作

创建表

python 复制代码
if __name__ == '__main__':
    # 删除所有表,注意这条是危险命令,会将模型类对应数据库中的表物理删除。在实际生产环境下勿用。
    db.drop_all()
    # 创建所有表
    db.create_all()

添加数据

python 复制代码
# 创建一个 father对象
f = Father(name='小头爸爸')
# 将数据添加到会话
db.session.add(f)
# 提交会话数据
db.session.commit()
​
# 创建两个Son对象,这里利用到father对象id,需要先将Father对象提交才能拿到id
s = Son(name='大头儿子', father_id=f.id)
s1 = Son(name='中头儿子', father_id=f.id)
# 同时添加多个数据,接收一个列表做参数
db.session.add_all([s, s1])
# 提交会话数据
db.session.commit()

事务管理

python 复制代码
# 创建一个 mother
m = Father(name='围裙妈妈')
db.session.add(m)
​
# 创建了一个妈妈,但是我们这里是Father类,需要回滚会话
db.session.rollback()

删除数据

python 复制代码
# 删除演员表中的'吴孟达'
# 将数据查询出来
actor = Cast.query.filter(Cast.name=='吴孟达').first()
# 删除对象
db.session.delete(actor)
# 提交到数据库
db.session.commit()

更新数据

python 复制代码
# 第一种方式:查询后修改
# 先将'梁小龙'查询出来
actor = Cast.query.filter(Cast.name=='梁小龙').first()
# 将'梁小龙'的名字改成'火云邪神'
actor.name = '火云邪神'
db.session.add(actor)
db.session.commit()
​
# 第二种方式:update方式
# 将'朱茵'修改成'紫霞仙子'
Cast.query.filter(Cast.name=='朱茵').update({'name':'紫霞仙子'})
db.session.commit()

5. 数据查询

基本查询方法

方法 作用
all() 返回数据库中所有数据,列表形式返回
first() 返回查询的第一个结果,如果未查到,返回None
first_or_404() 返回查询的第一个结果,如果未查到,返回404
get() 返回指定主键对应的行,如不存在,返回None
get_or_404() 返回指定主键对应的行,如不存在,返回404
count() 返回查询结果的数量
paginate() 返回一个Paginate对象,它包含指定范围内的结果

查询过滤器

过滤器 说明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit 使用指定的值限定原查询返回的结果
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询

查询示例

python 复制代码
# filter_by 精确匹配查询,条件只能是本表的字段
Cast.query.filter_by(name='周星驰').all()
​
# first()返回查询到的第一个对象
Cast.query.first()
​
# all()返回查询到的所有对象
Cast.query.all()
​
# filter 模糊查询
Cast.query.filter(Cast.name.startswith('周'))
Cast.query.filter(Cast.name.endswith('龙'))
Cast.query.filter(Cast.name=='周星驰').all()
​
# like 正则模糊匹配
Cast.query.filter(Cast.name.like('周%%'))

逻辑运算查询

python 复制代码
from sqlalchemy import and_, or_, not_
​
# 查询名字为'周星驰'并且movie_id为2的演员数据
cast.query.filter(and_(cast.name=='周星驰', cast.movie_id==2)).all()
​
# 查询名字为'周星驰'或者id为2的演员数据
cast.query.filter(or_(cast.name=='周星驰', cast.movie_id==2)).all()
​
# 查询名字不为'周星驰'的演员
cast.query.filter(not_(cast.name=='周星驰')).all()

关联查询

python 复制代码
# 查询名字为朱茵的演员,并且查出她出演的电影
# 查询出演员'朱茵'
actor = Cast.query.filter(Cast.name=='朱茵').all()
# 直接通过 relationship 中定义的 backref 属性可以直接查询出演员对应的电影
movie = actor[0].Movie
# 通过电影直接查询出所有演员
actors = movie.cast

添加repr方法

python 复制代码
def __repr__(self):
    return "Father: %s" % self.name

6. 完整示例

python 复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
​
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@192.168.20.233:3306/py'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
​
class Movie(db.Model):
    """创建一个电影模型类"""
    # 表名
    __tablename__ = 'movie'
    # id主键列,整数类型,自增
    id = db.Column(db.Integer, primary_key=True)
    # name,可变长字符串类型
    name = db.Column(db.String(20))
    # 关系字段,不是数据库中真实存在的字段,而是为了方便查询添加的属性
    cast = db.relationship('Cast', backref='Movie')
    
    def __repr__(self):
        return "Movie: %s " % self.name
​
class Cast(db.Model):
    """演员模型类"""
    # id主键列,整数类型,自增
    id = db.Column(db.Integer, primary_key=True)
    # name,可变长字符串类型
    name = db.Column(db.String(20))
    # 外键关联id
    movie_id = db.Column(db.Integer, db.ForeignKey('movie.id'))
    
    def __repr__(self):
        return "Cast: %s " % self.name
​
if __name__ == '__main__':
    # 删除所有表
    db.drop_all()
    # 创建所有表
    db.create_all()
    
    # 创建电影数据
    m1 = Movie(name='大话西游')
    m2 = Movie(name='功夫')
    db.session.add_all([m1, m2])
    db.session.commit()
    
    # 创建演员数据
    cast_list = []
    for i in ['周星驰','朱茵','吴孟达','莫文蔚']:
        c = Cast(name=i, movie_id=m1.id)
        cast_list.append(c)
    for i in ['周星驰','梁小龙','元华']:
        c = Cast(name=i, movie_id=m2.id)
        cast_list.append(c)
    
    db.session.add_all(cast_list)
    db.session.commit()
相关推荐
ejinxian6 分钟前
MySQL/Kafka数据集成同步,增量同步及全量同步
数据库·mysql·kafka
未来之窗软件服务10 分钟前
数据库优化提速(一)之进销存库存管理—仙盟创梦IDE
数据库·sql·数据库调优
深盾安全27 分钟前
Python 装饰器详解
python
前端小趴菜0535 分钟前
python - 数据类型转换
python
Mapmost1 小时前
信创浪潮下的GIS技术变革:从自主可控到生态繁荣
数据库
跟橙姐学代码1 小时前
学Python必须迈过的一道坎:类和对象到底是什么鬼?
前端·python
foundbug9991 小时前
Node.js导入MongoDB具体操作
数据库·mongodb·node.js
天天进步20151 小时前
Node.js中的Prisma应用:现代数据库开发的最佳实践
数据库·node.js·数据库开发
卡洛斯(编程版1 小时前
(1) 哈希表全思路-20天刷完Leetcode Hot 100计划
python·算法·leetcode
FreakStudio2 小时前
一文速通 Python 并行计算:教程总结
python·pycharm·嵌入式·面向对象·并行计算