flask 之数据库及ORM模型

一、数据库连接池

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 如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它。

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 日期,存储Pythondatetime.date 对象 date类型
Time 时间,存储Pythondatetime.time 对象 time类型
DateTime 时间和日期,存储Pythondatetime 对象 datetime类型
Float 浮点类型 float类型
Double 双精度浮点类型,比浮点类型小数位精度更高。 double类型,占据64位。
Boolean 布尔值 tinyint类型
Enum 枚举类型 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(版本号)


'

不将就
原文地址:https://www.cnblogs.com/nq31/p/14338856.html