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(版本号)


'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值