一、数据库连接池
python用于实现数据库连接池的模块是DBUntils
DBUntils有两种模式,一种是PersistentDB,一种是PooledDB
1、PersistentDB
该模式,会为每一个线程创建一个连接,创建的连接只可以给该线程使用,不能给其他线程使用,线程调用close方法后,连接会放到连接池,等待该线程的再次使用,直到线程终止时,连接才会关闭。这个模式,需要自己控制线程数量
# -*-coding:utf-8 -*-
import pymysql
from DBUtils.PersistentDB import PersistentDB
POOL=PersistentDB(
creator=pymysql,# 使用链接数据库的模块
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
ping=0, # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
closeable=False,# 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
threadlocal=local, # 如果为none,用默认的threading.Loacl对象,否则可以自己封装一个local对象进行替换
host='127.0.0.1',
port=3306,
user='root',
password='root',
database='pooldb',
charset='utf8'
)
def func():
conn=POOL.connection(shareable=False)
cursor=conn.cursor()
cursor.execute('select * from tb1')
result = cursor.fetchall()
cursor.close()
conn.close()
func()
2、PooledDB
该模式下,是创建一批连接到连接池,供所有线程共享使用,一般都推荐用这种模式
# -*-coding:utf-8 -*-
import pymysql
from DBUtils.PooledDB import PooledDB
POOL = PooledDB(
creator=pymysql, # 使用链接数据库的模块
maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached=5, # 链接池中最多闲置的链接,0和None不限制
maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
ping=0, # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
host='127.0.0.1',
port=3306,
user='root',
password='root',
database='pooldb',
charset='utf8'
)
def func():
conn=POOL.connection(shareable=False)
cursor=conn.cursor()
cursor.execute('select * from tb1')
result = cursor.fetchall()
cursor.close()
conn.close()
func()
二、SQLALchemy
1、简介
定义:SQLAlchemy是一个基于Python实现的ORM框架。提供了SQL工具包及对象关系映射(ORM)工具,该框架建立在 DB API之上,使用关系对象映射进行数据库操作。
本质:将类和对象转换成SQL,然后使用数据库API执行SQL并获取执行结果。
组成部分:
- Engine 框架的引擎
- Connection Pooling 数据库连接池
- Dialect 选择连接数据库的DB API种类
- Schema/Types 架构和类型 SQL Exprression Language,SQL表达式语言
注意:SQLAlchemy本身无法操作数据库,必须依赖pymysql等第三方插件,它不支持修改字段
2、简单使用(执行原生sql)
# -*-coding:utf-8 -*-
from sqlalchemy import create_engine
import sqlalchemy
from sqlalchemy.engine.base import Engine
# 生成一个engine对象
engine=create_engine(
"mysql+pymysql://root:root@127.0.0.1:3306/flaskdb?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 等待线程池中线程最多等待时间
pool_recycle=-1 #多久对线程池的线程进行重置
)
#创建连接(执行原生sql)
conn=engine.raw_connection()
# 获取游标对象
cursor=conn.cursor()
# 数据库操作
# 创建表
cursor.execute('create table test3 (name char(32),age int)')
# 插入数据
cursor.execute('insert into test (name) value(1)')
# 删除表
cursor.execute('drop table test')
cursor.execute('show tables')
res=cursor.fetchall()
print(res)
3、orm表创建和表关系
(1)创建表、删除表
# -*-coding:utf-8 -*-
import datetime
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
# 导入字段和字段属性
from sqlalchemy import Column,Integer,String,Text,ForeignKey,DateTime,UniqueConstraint,Index
# 创建一个基类
Base=declarative_base()
# 表模型类
class User(Base):
__tablename__='user' # 表名
id=Column(Integer,primary_key=True) #设置为主键
name=Column(String(32),index=True,nullable=False) #不能为空,索引
email=Column(String(32),unique=True) # 唯一
# 注意:datetime.datetime.now不能加括号,加了括号,以后永远是当前时间,不会再改变
# datetime.now:插入数据的时间
# datetime.now(): 程序部署的时间,每条数据时间都是同样,且固定不变的
create_time=Column(DateTime,default=datetime.datetime.now)
extra=Column(Text,nullable=True)
# __table_args__ 类似django的Meta
__table_args__=(
UniqueConstraint('id', 'name', name='uix_id_name'), #联合唯一
Index('ix_id_name', 'name', 'email'), #索引
)
def init_db():
engine=create_engine(
"mysql+pymysql://root:root@127.0.0.1:3306/flaskdb?charset=utf8",
max_overflow=0,
pool_size=5,
pool_timeout=30,
pool_recycle=-1
)
# 通过engine对象来创建表
Base.metadata.create_all(engine)
# 删除表
Base.metadata.drop_all(engine)
if __name__=='__main__':
init_db()
(2)一对多、多对多
# -*-coding:utf-8 -*-
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.engine import create_engine
Base = declarative_base()
# book和publish 是一对多
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
publish_id = Column(Integer, ForeignKey("publish.id"))
class Author(Base):
__tablename__ = 'author'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
class Publish(Base):
__tablename__ = 'publish'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
#book和auhtor是多对多
class Book2Author(Base):
__tablename__ = 'book_author'
id = Column(Integer, primary_key=True, autoincrement=True)
book_id = Column(Integer, ForeignKey('book.id'))
author_id = Column(Integer, ForeignKey('author.id'))
def init_db():
engine = create_engine(
"mysql+pymysql://root:root@127.0.0.1:3306/flaskdb?charset=utf8",
max_overflow=0,
pool_size=5,
pool_timeout=30,
pool_recycle=-1
)
# 通过engine对象来创建表
Base.metadata.create_all(engine)
if __name__ == '__main__':
init_db()
4、单表基本操作(增删改查)
# -*-coding:utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.sql import text
from sqlalchemy.orm import sessionmaker, relationship
from model import Author
# 生成一个引擎engine
engine = create_engine(
"mysql+pymysql://root:root@127.0.0.1:3306/flaskdb?charset=utf8",
max_overflow=0,
pool_size=5,
)
# 创建一个会话类
Session = sessionmaker(bind=engine)
# 实例化一个会话对象
session = Session()
# ------------增--------------
# 创建一个对象
obj1 = Author(name='hello')
# # 将对象添加到会话对象中
session.add(obj1)
# # 批量增加
session.add_all([
Author(name='ha'),
Author(name='ha1'),
Author(name='ha2'),
])
session.commit()
# ------------删除-------------
session.query(Author).filter(Author.id == 1).delete()
session.commit()
# -------------改--------------
session.query(Author).filter(Author.id>3).update({"name":"nq31"})
# 第二种:类似Django的F查询
# 注意:如果是字符串相加,synchronize_session要设置成False,数字相加则设置成evaluate
session.query(Author).filter(Author.id==2).update({Author.name:Author.name+'good'},synchronize_session=False)
session.query(Author).filter(Author.id>0).update({"id":Author.id+1},synchronize_session="evaluate")
# ------------查---------------
r1=session.query(Author).all()
# 对name列进行重命名,只取name列
r2=session.query(Author.name.label('名字'),Author.name).all()
# 注意:filter传的是表达式,filter_by传的是参数,first()是只取第一个
r3=session.query(Author).filter(Author.name=='nq31').all()
r4=session.query(Author).filter_by(name='nq31').all()
r5=session.query(Author).filter_by(name='nq31').first()
# 查询id<5,名字为nq31的数据,:value,:name都是占位符
r6=session.query(Author).filter(text("id<:value and name=:name ")).params(value=5,name='nq31').order_by(Author.id).all()
# 自定义查询语句
r7 = session.query(Author).from_statement(text("SELECT * FROM Author where name=:name")).params(name='ha1').all()
# 返回结果是:[<model.Author object at 0x000001DA49136390>] 类型
session.commit()
注意:查询的返回值是列表,query()的参数如果是表名,则表示获取所有表字段,如果是字段名,则表示只获取该字段
5、数据库高级操作
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from model import Author
# 生成一个引擎engine
engine = create_engine(
"mysql+pymysql://root:root@127.0.0.1:3306/flaskdb?charset=utf8",
max_overflow=0,
pool_size=5,
)
# 创建一个会话类
Session = sessionmaker(bind=engine)
# 实例化一个会话对象
session = Session()
# 条件
res = session.query(Author).filter_by(name='nq31').all()
# 表达式,and条件连接
# 查询id>1且名字为nq31的作者
res = session.query(Author).filter(Author.id > 1, Author.name == 'nq31').all()
# 查询id在(1,3)之间的作者
res = session.query(Author).filter(Author.id.between(1, 3), Author.name == 'nq31').all()
# 注意下划线,in_是取出id为2,3,4的元素
res = session.query(Author).filter(Author.id.in_([2, 3, 4])).all()
# # ~非,除 xxx 外
res = session.query(Author).filter(~Author.id.in_([1, 3, 4])).all()
# # 二次筛选 也就是嵌套
res = session.query(Author).filter(Author.id.in_(session.query(Author.id).filter_by(name='nq31'))).all()
from sqlalchemy import and_, or_
# # or_包裹的都是or条件,and_包裹的都是and条件
# 查询id>3 且 name=nq31的数据
res = session.query(Author).filter(and_(Author.id > 3, Author.name == 'nq31')).all()
# 查询id<4 或 name=nq31的数据
res = session.query(Author).filter(or_(Author.id < 4, Author.name == 'nq31')).all()
res = session.query(Author).filter(
or_(
Author.id < 2,
and_(Author.name == 'eric', Author.id > 3),
# Author.extra != ""
)).all()
# # 通配符,查询名字以n开头的数据
res = session.query(Author).filter(Author.name.like('n%')).all()
# 查询名字不以e开头的数据
res = session.query(Author).filter(~Author.name.like('n%')).all()
# # 限制,用于分页,区间
res = session.query(Author)[1:2]
# # 排序,根据name降序排列(从大到小)
res = session.query(Author).order_by(Author.name.desc()).all()
# # 第一个条件重复后,再按第二个条件升序排
res = session.query(Author).order_by(Author.name.desc(), Author.id.asc()).all()
#
# # 分组
from sqlalchemy.sql import func
res = session.query(Author).group_by(Author.name).all()
# # 分组之后取最大id,id之和,最小id
res = session.query(
func.max(Author.id),
func.sum(Author.id),
func.min(Author.id)).group_by(Author.name).all()
# # haviing筛选
res = session.query(
func.max(Author.id),
func.sum(Author.id),
func.min(Author.id)).group_by(Author.name).having(func.min(Author.id) > 2).all()
6、基于scoped_session实现线程安全
(1) 导入scoped_session
from sqlalchemy.orm import scoped_session
(2) 使用方法:
把原来会话类实例化的时候,改成session=scoped_session(Session)
# -*-coding:utf-8 -*-
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from model import Book
engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/flaskdb", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
# 注意:scoped_session类并没有继承Session,但是,它有session的所有方法
session = scoped_session(Session)
obj = Book(name='天行九歌', publish_id=1)
session.add(obj)
session.commit()
7、多表操作
(1) 模型表
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
publish_id = Column(Integer, ForeignKey("publish.id"))
# publish字段不会在数据库生成,主要是用来作关联,
# relationship(‘关联表类名',backref='反向查询属性’)
# 如下,通过book.publish可以拿到publish对象,通过Publish.books可以拿到所有book对象
publish=relationship('Publish',backref='books')class Publish(Base):
__tablename__ = 'publish'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
(2)一对多操作
# -*-coding:utf-8 -*-
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine
from model import Book, Publish
engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/flaskdb", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()
# --------------添加-----------------
# ------第一种------
obj=Publish(name='广州出版社')
session.add(obj)
b_obj=Book(name='秦时明月',publish_id=3)
session.add(b_obj)
# ------第二种(前提有设置relationship)-------
obj=Book(name='战争',publish=Publish(name='广州出版社'))
session.add(obj)
# ---------第三种(反向,也需要设置relationship)----------
p_obj=Publish(name='广州出版社')
p_obj.book=[Book(name='艺术'),Book(name='蓝图')]
session.add(p_obj)
# -------------查询---------------
# 1、relationship正向查询
res=session.query(Book).first()
print(res.publish.name)
print(res.name)
# 2、relationship反向查询,根据relationship中backref设置的参数books反查询
res=session.query(Publish).first()
for book in res.books:
print(book.name)
print(res.name)
# 根据join来实现链表查询
book_list=session.query(Book,Publish).join(Publish,isouter=True).all()
print(book_list)
for l in book_list:
print(l[0].name,l[1].name)
# 根据relationship来链表查询
book_list1=session.query(Book).all()
for l in book_list1:
print(l.name,l.publish.name)
session.commit()
修改跟删除操作跟普通一样
(3)多对多表操作
表模型
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
publish_id = Column(Integer, ForeignKey("publish.id"))
# publish字段不会在数据库生成,主要是用来作关联,
# relationship(‘关联表类名',backref='反向查询属性’)
# 如下,通过book.publish可以拿到publish对象,通过Publish.books可以拿到所有book对象
publish=relationship('Publish',backref='books')
class Author(Base):
__tablename__ = 'author'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False)
# secondary参数是表示通过哪张表关联
books=relationship('Book',secondary='book_author',backref='authors')
class Book2Author(Base):
__tablename__ = 'book_author'
id = Column(Integer, primary_key=True, autoincrement=True)
book_id = Column(Integer, ForeignKey('book.id'))
author_id = Column(Integer, ForeignKey('author.id'))
操作
# -------------多对多添加------------------
# 1、反向添加
book_obj=Book(name='斗罗大陆')
book_obj.authors=[Author(name='唐家三少'),Author(name='唐三')]
session.add(book_obj)
# 2、正向添加
author_obj=Author(name='三少',books=[Book(name='新世纪',publish_id=1),Book(name='爬虫三件套',publish_id=2)])
session.add(author_obj)
# --------------多对多查询--------------
# 1、反向查询
res=session.query(Book).first()
for r in res.authors:
print(r.name)
# 2、正向查询
res=session.query(Author).first()
for r in res.books:
print(r.name)
# 1、基于对象查询
res=session.query(Author).filter(Author.name=='唐家三少').all() #all返回的是列表
for r in res[0].books:
print(r.name)
# 2、基于链表查询
'''原生sql语句
select Book.name from Book inner join Author on Author.id=Book2Author.author_id inner join Book2Author on Book.id=Book2Author.id where Author.name='唐家三少'
'''
res=session.query(Book.name).join(Book2Author).join(Author).filter(Book2Author.book_id==Book.id,Book2Author.author_id==Author.id,Author.name=='唐家三少').all()
for r in res:
print(r.name)
(4)其他操作
# 连表
res=session.query(Book,Publish).filter(Book.publish_id==Publish.id).all()
'''
join连表
join()括号内放连表条件,也就是原生sql语句中on后面的条件
注意:默认是inner join ,如果isouter=True 则表示左连接,left join,没有右连接,可以两个表位置交换一下,来实现右链接
'''
res=session.query(Book).join(Publish).all()
for r in res:
print(r.name,r.publish.name,r.id)
res=session.query(Book).join(Publish,Book.publish_id==Publish.id,isouter=True).all()
for r in res:
print(r.name,r.publish.name,r.id)
'''
union用于合并两个或多个结果集合
union和union_all区别:
union:不包括重复行,会按默认规则排序
union_all:包括重复行,不进行排序
'''
res1=session.query(Book.name).filter(Book.id<4)
res2=session.query(Publish.name).filter(Publish.id<3)
res=res1.union(res2).all()
print(res)
r=res1.union_all(res2).all()
print(r)
三、Flask-SQLAlchemy
1、简介
Flask_SQLAlchemy是基于SQLAlchemy开发的扩展组件,也是ORM框架
安装:pip install flask-sqlalchemy
2、配置
说明 | |
---|---|
SQLALCHEMY_DATABASE_URI | 连接数据库。示例:mysql://username:password@host/post/db?charset=utf-8 |
SQLALCHEMY_BINDS | 一个将会绑定多种数据库的字典。 更多详细信息请看官文 |
SQLALCHEMY_ECHO | 调试设置为true |
SQLALCHEMY_POOL_SIZE | 数据库池的大小,默认值为5。 |
SQLALCHEMY_POOL_TIMEOUT | 连接超时时间 |
SQLALCHEMY_POOL_RECYCLE | 自动回收连接的秒数。 |
SQLALCHEMY_MAX_OVERFLOW | 控制在连接池达到最大值后可以创建的连接数。当这些额外的 连接回收到连接池后将会被断开和抛弃。 |
SQLALCHEMY_TRACK_MODIFICATIONS |
3、连接数据库
# -*-coding:utf-8 -*-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app=Flask(__name__)
# mysql+pymysql://用户名:密码@127.0.0.1:3306/数据库
DB_URI='mysql+pymysql://root:root@127.0.0.1:3306/flaskdb?charset=utf8mb4'
app.config['SQLALCHEMY_DATABASE_URI']=DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False
# SQLALCHEMY_TRACK_MODIFICATIONS这个配置变量决定是否追踪对象的修改,这用于FLask- SQLALchemy的事件通知系统。这个配置键默认值为None,如果没有特殊需要我们把它设置为Flase, 避免造成一些没必要的性能浪费
db=SQLAlchemy(app)
4、数据库模型类中字段和参数
4.1、表名指定
class Book(Base):
__tablename__ = 'book'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32), nullable=False)
__tablename__:用来指定表名,如果没有写__tablename__,则默认将类名转为小写,作为表名
注意:如果类名是多个单词,则转为小写后并使用下划线分隔,如: BookAuhtor类 - ->book_author
db.Colunm:表示字段
4.2、常用字段类型表
说明 | 映射到数据库对应类型 | |
---|---|---|
Integer | 整数 | int类型 |
String | 字符串,String 类内可选择length 参数的值用于设置最大字符个数 | varchar类型 |
Text | 用于储存较长的Unicode文本,,理论上可以储存65535个字节 | text类型 |
Date | 日期,存储Python 的datetime.date 对象 | date类型 |
Time | 时间,存储Python 的datetime.time 对象 | time类型 |
DateTime | 时间和日期,存储Python 的datetime 对象 | datetime类型 |
Float | 浮点类型 | float类型 |
Double | 双精度浮点类型,比浮点类型小数位精度更高。 | double类型,占据64位。 |
Boolean | 布尔值 | tinyint类型 |
Enum | 枚举类型 |
4.3、Column常用参数表
说明 | |
---|---|
primary_key | 如果设为True,该列就是表的主键 |
unique | 如果设为True,该列每个值唯一,也就是该字段不允许出现重复值 |
index | 如果设为True,为这列创建索引,用于提升查询效率 |
nullable | 如果设为True,这列允许使用空值,反之则不允许使用空值。 |
server_default | 为这列定义默认值, 默认值只支持字符串,其他类型需要db.text()方法指定 |
default | 为这列定义默认值,但是该约束并不会真正映射到表结构中,该约束只会在ORM层面实现(不推荐使用) |
comment | 该字段的注释 |
name | 可以使用该参数直接指定字段名 |
autoincrement |
上表中server_default的常用配置如下:
配置默认值类型 | 代码 |
---|---|
更新datatime时间 | server_default = db.text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") |
当前的datatime时间 | server_default = db.text("CURRENT_TIMESTAMP") |
数字 | server_default=“数字” |
布尔 | server_default=db.text('True') / server_default=db.text('False')/ server_default='数字' |
5、数据库操作
5.1、建表
# -*-coding:utf-8 -*-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# mysql+pymysql://用户名:密码@127.0.0.1:3306/数据库
DB_URI = 'mysql+pymysql://root:root@127.0.0.1:3306/flaskdb?charset=utf8mb4'
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# SQLALCHEMY_TRACK_MODIFICATIONS这个配置变量决定是否追踪对象的修改,这用于FLask- SQLALchemy的事件通知系统。这个配置键默认值为None,如果没有特殊需要我们把它设置为Flase, 避免造成一些没必要的性能浪费
db = SQLAlchemy(app)
class UserInfo(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(20), nullable=False)
class School(db.Model):
__tablename__="school"
id = db.Column(db.Integer,primary_key=True,nullable=False,autoincrement=True,comment='ID')
name = db.Column(db.String(30),nullable=False,server_default='',comment='学校名称')
area=db.Column(db.String(30),nullable=False,server_default='广州',comment='学校地址') # 默认参数‘广州’
score=db.Column(db.Integer,nullable=False,server_default='100') # 默认参数 100
# 创建所有库
db.create_all()
# 删除所有库
db.drop_all()
5.2、增删改查
常用的过滤器
过滤器 | 说明 |
---|---|
filter() | 使用指定的规则过滤记录相当于sql的where约束条件,返回一个新查询 |
filter_by() | 同filter原理,不同的是查询的时要使用关键字参数,返回一个新查询 |
limit() | 使用指定的值限制原查询返回的结果的数量,返回一个新查询 |
offset() | 偏移原查询返回的结果,返回一个新查询 |
order_by() | 根据指定条件对原查询结构进行排序,返回一个新查询 |
group_by() | 根据指定条件对原来查询结构进行分组,返回一个新查询 |
(1) 增加
school01=School(name='北京大学',area='北京',score=100)
school02=School(name='北京大学',area='北京',score=100)
# 增加单条数据 用add
db.session.add(school01)
# 增加多条数据 用add_all
db.session.add_all([school01,school02])
db.session.commit()
(2)查询
# all() 获取所有结果
school=School.query.all()
# first() 获取第一个结果
school=School.query.first()
# get() 返回指定主键值(id字段)的记录
school=School.query.get(3)
# filter()过滤,相当于where约束条件
school=School.query.filter(School.area=='北京').all()
# filter_by: 通filter一样,它使用的是关键字参数查询,不能用在多表查询
school=School.query.filter_by(area='北京').all()
#db.session.query(模型类,也就是表类)可以进行多表查询
obj=db.session.query(School).filter(School.name=='北京大学').first()
(3)修改
# 更改,先找到更改对象,修改对象的属性就可以
obj=School.query.filter(School.area=='北京').first()
obj.score=700
db.session.commit()
(4)删除
同样,也是先找到对象,然后调用db.session.delete(对象)删除
obj= School.query.filter(School.name=='北京大学').first()
db.session.delete(obj)
db.session.commit()
总结:flask_sqlalchemy用法总体跟sqlalchemy很类似。
为了解决每次更新模型,都需要先删除原来的模型表,导致原来数据被删除的问题,可以使用flask-migrate扩展组件来解决
四、flask-migrate
1、flask-migrate基本使用方法
(1)先安装
pip install flask-migrate
(2)具体使用案例,manage.py文件如下:
注意:flask-migrate需要和flask-script配合使用
# -*-coding:utf-8 -*-
# 导入Migrate,MigrateCommand模块
from flask_migrate import Migrate,MigrateCommand
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
DB_URI = 'mysql+pymysql://root:root@127.0.0.1:3306/flaskdb?charset=utf8mb4'
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
manager=Manager(app)
# Migrate()第一个参数是flask实例,第二个参数SQLAlchemy数据库实例
Migrate(app,db)
# 在manager实例中添加db 子命令)
manager.add_command('db',MigrateCommand)
# 定义模型类
class School1(db.Model):
__tablename__="school1"
id = db.Column(db.Integer,primary_key=True,nullable=False,autoincrement=True,comment='ID')
name = db.Column(db.String(30),nullable=False,server_default='',comment='学校名称')
area=db.Column(db.String(30),nullable=False,server_default='广州',comment='学校地址') # 默认参数‘广州’
score=db.Column(db.Integer,nullable=False,server_default='100') # 默认参数 100
if __name__=='__main__':
manager.run()
2、flask-migrate具体命令
注意:切入到manage.py所在目录中,就可以执行以下命令
2.1、初始化,只执行一次,创建migrations文件夹
#命令格式:python 文件 自定义的命令 init,
# manager.add_command('db',MigrateCommand),db就是自定义命令
python manage.py db init
2.2、创建迁移文件,等同于Django中 makemigartions
python manage.py db migrate
# python manage.py db migrate -m '注释信息'
2.3、更新数据库,等同于Django中migrate
python manage.py db upgrade
# 注意:upgrade 是将改动迁移到数据库中
2.4、回退版本
# 1、查看历史版本
python manage.py db history
# 返回:<base> -> 95afb6893815 (head), empty message
# 2、回退到指定的版本
python manage.py db downgrade 95afb6893815(版本号)
'