Flask 06

Flask:

SQLalchemy 快速的插入数据

sqlalchemy是什么?

SQLalchemy是python的SQL工具包和对象关系映射器,可以让应用程序开发人员
使用SQL的功能和灵活性。

SQLalchemy 的理念:

SQL数据库与对象集合目标不同,它需要关注更大的数据容量和更高的性能,而对
象集合则和数据表或数据行的目标不同,他需要跟好的数据抽象,SQLalchemy的
设计目的就是适配这两个原则。

	SQLalchemy把数据库当做是一个关系型袋鼠引擎,不只是数据表的一个集
	合,数据不仅可以从数据库中查询出来,也可以从数据表关联后形成的逻辑数
	据和其他查询,这些元素可以结合形成更大的数据结构。
    SQLalchemy 组件中最有的名的就是他的对象关系映射器(ORM),是一个提
	供数据映射器模式的可选组件,利用这个组件,类就可以开放式多种方式映射
	到数据库上,允许对象模型的设计和数据库架构的设计,一开始就以分离的方
	式各自进行各自的开发。

使用:

安装:
pip install SQLalchemy

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

第一步:生成一个engine对象:
engine=create_engin(
"mysql+pymysql://用户名:密码 @127.0.0.1:3306/数据库名称",
        max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
    pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
)

第二步:拿到一个Session类,传入engine
	Session=seaaionmaker(bind=engin)
    
第三步:拿到session对象,相当于是连接诶对象(会话)
	session=Session()
    
第四步:增加数据
	book =Book(name='三国演义')
    session.add(book)
    session.commit()  # 提交会话,这个能够保证数据的一致性
 
第五步:关闭session对象
	session.colse()

scoped_session 线程安全

基本使用:

from sqlalchemy.orm import scoped_session
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# 第一步:生成engine对象
engine = create_engine(
    "mysql+pymysql://root@127.0.0.1:3306/aaa",
    max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
    pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第二步:拿到一个Session类,传入engine
Session = sessionmaker(bind=engine)
# 这样线程不安全
# session = Session()

'做成线程数据安全:'
# 在flask 中内部使用了local对象,取当前线程的session,如果当前线程有,
就直接返回使用,没有的话,就创建一个,放到local中。
这里的session是 scoped_session 的对象

session=scoped_session(Session)
"以后在全局使用session即可,就能保证它的线程的安全了"

加在类上的装饰器

# 我们在使用session 是scoped_session 的对象,类上是没有属性和方法的,
但是我们在使用的过程中,确能够使用到

session =scoped_session (Session)

def index():
    print('执行了')
    
def wrapper(func):
    def inner(*args,**kwargs):
        res=func()
        res.name='Andy'
        res.index=index
        return res
    return inner

@wrapper  # 语法糖会把person当做参数传入到装饰器中
Person=wrapper(Person)
class Person:
    ...
    
p =Person()

# 可以直接执行
p.index()

类作为装饰器来使用:

    class Wrapper():
        def __init__(self, func):
            self.func = func

        def __call__(self, *args, **kwargs):
            # 前面加代码
            print('在前面的代码')
            res = self.func(*args, **kwargs)
            # 后面加代码
            print('在后面的代码')
            return res
        
        
@Wrapper  # add=Wrapper(add)--->触发Wrapper的__init__---->现在add是Wrapper类的对象
def add():
    print('执行')   

数据的基本增删改查

from models import User, Book
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
from sqlalchemy.sql import text
engine = create_engine("mysql+pymysql://root@127.0.0.1:3306/aaa")
Session = sessionmaker(bind=engine)
session = scoped_session(Session)

1.增加 :add  add_all
user=User(name='lqz',email='44@qq.com')
user1=User(name='yyy',email='3@qq.com')
book=Book(name='人生')
session.add(book)
session.add_all([user,user1,book]) # 里面可以是多个不同的对象,只要是在models中任意的表模型对象


2.查询 :filter  filter_by  
filter :写条件   filter_by:等于的值

filter:
	1.session.query(User) # 括号中写表模型,可以写多个(连表操作)
	2.filter 过滤条件,必须要写表达式 == !=
    
all:结果是普通列表  first:第一个
    
	user = session.query(User).filter(User.name == 'lqz').first()

	user = session.query(User).filter(User.name != 'lqz').all()
    
    
filter_by :直接写等式
   user = session.query(User).filter_by(name='lqz').first() 
  user = session.query(User).filter_by(id=2).first() 
    
3.删除 (需要先查到才能删除) # filter 或filter_by 查询的结果,不要all 或者first出来,直接 .delete() 即可
	res = session.query(User).filter_by(id=2).delete()
session.commit() # 一定要提交

res :是执行后结果的行数


4.修改(需要先查询到才能改)
方式一:update 修改
	res = session.query(User).filter_by(id=3).update({"name" : "彭于晏"}

方式二: 使用对象修改
	res = session.query(User).filter_by(id=3).first()
    res.name='andy'
    session.add(res)  # add 如果有主键,就是修改,如果没有主键就是新增

高级查询:

1.查询所有  是list对象
res = session.query(User).all()  # 得到的结果是个普通列表

2.只查询某几个字段
# 相当于是select name as xx,email from user;
res = session.query(User.name.label('xx'), User.email)

res:打印是原生的sql

for item in res.all():
   print(item[0])

filter 传的是表达式, filter_by 传的是参数
	res = session.query(User).filter(User.name == "lqz").all()
	res = session.query(User).filter_by(name='lqz099').all()
    
3.查询所有,使用占位符(了解)  :value   :name
# select * from user where id <20 or name=lqz099
	res = session.query(User).filter(text("id<:value or name=:name")).params(value=10, name='lqz099').all()
    
4. 自定义查询(了解)
	使用 from_statement 写纯原生sql
	res=session.query(User).from_statement(text("SELECT * FROM users where email=:email")).params(email='3@qq.com').all()
    print(res[0].name) 
    
5. 高级查询  使用条件查询
#表达式,使用and 条件链接
	res = session.query(User).filter(User.id > 1, User.name == 'lqz099').all() # and条件
    
# 使用between (在。。。之间)
	res = session.query(User).filter(User.id.between(1, 9)).all()
    
# in  (在。。。里面)
	res = session.query(User).filter(User.id.in_([1,3,4])).all()
    
# ~ 非  (除。。。之外)
	res = session.query(User).filter(~User.id.in_([1,3,4])).all()
    
# 二次筛选
	res = session.query(User).filter(~User.id.in_(session.query(User.id).filter_by(name='lqz099'))).all()
    
# and or条件
from sqlalchemy import and_, or_
# or_ 包裹的都是or条件,and_ 包裹的是and条件
	res = session.query(User).filter(and_(User.id >= 3, User.name == 'lqz099')).all()  #  and条件
    res = session.query(User).filter(
     or_(
         User.id < 2,
         and_(User.name == 'lqz099', User.id > 3),
         User.extra != ""
    )).all()
    
    
# 通配符,以e开头,不以e开头
	res = session.query(User).filter(User.email.like('%@%')).all()
    
# 分页
# 一页2条,查第5页
# res = session.query(User)[2*5:2*5+2]

# 排序,根据name降序排列(从大到小)
	res = session.query(User).order_by(User.email.desc()).all()
    
# 第一个条件重复后,再按第二个条件升序排
	res = session.query(User).order_by(User.name.desc(), User.id.asc())
    
# 分组查询  5个聚合函数
from sqlalchemy.sql import func

	res = session.query(User).group_by(User.extra)  # 如果是严格模
	式,就报错
    # 分组之后取最大id,id之和,最小id  和分组的字段
# res = session.query(
#     User.extra,
#     func.max(User.id),
#     func.sum(User.id),
#     func.min(User.id)).group_by(User.extra).all()
# for item in res:
#     print(item[2])


	res = session.query(
    func.max(User.id),
    func.sum(User.id),
    func.min(User.id)).group_by(User.extra).having(func.max(User.id) > 2)

原生sql

### 方式一:
# 第一步:导入
from sqlalchemy import create_engine
# 第二步:生成引擎对象
engine = create_engine(
    "mysql+pymysql://root@127.0.0.1:3306/cnblogs",
    max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
    pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第三步:使用引擎获取连接,操作数据库
conn = engine.raw_connection()
cursor=conn.cursor()
cursor.execute('select * from aritcle')
print(cursor.fetchall())



### 方式二:
from models import User, Book
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
engine = create_engine("mysql+pymysql://root@127.0.0.1:3306/aaa")
Session = sessionmaker(bind=engine)
session = scoped_session(Session)

# 2.0.9 版本需要使用text包裹一下,原来版本不需要
# cursor = session.execute(text('select * from users'))
# result = cursor.fetchall()
# print(result)

cursor = session.execute(text('insert into books(name) values(:name)'), params={"name": '红楼梦'})
session.commit()
print(cursor.lastrowid)

session.close()

django中执行原生sql

# 一对多关系
from sqlalchemy import create_engine
import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
from sqlalchemy.orm import relationship

# 第二步:执行declarative_base,得到一个类
Base = declarative_base()


class Hobby(Base):
    __tablename__ = 'hobby'
    id = Column(Integer, primary_key=True)
    caption = Column(String(50), default='篮球')


class Person(Base):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True)
    name = Column(String(32), index=True, nullable=True)
    # hobby指的是tablename而不是类名
    # 关联字段写在多的一方,写在Person中,跟hobby表中id字段做外键关联
    hobby_id = Column(Integer, ForeignKey("hobby.id"))

    # 跟数据库无关,不会新增字段,只用于快速链表操作
    # 基于对象的跨表查询:就要加这个字段,取对象  person.hobby     pserson.hobby_id
    # 类名,backref用于反向查询
    hobby = relationship('Hobby', backref='pers')  # 如果有hobby对象,拿到所有人 hobby.pers

    def __repr__(self):
        return self.name


engine = create_engine("mysql+pymysql://root@127.0.0.1:3306/aaa", )

# 把表同步到数据库  (把被Base管理的所有表,都创建到数据库)
Base.metadata.create_all(engine)

# 把所有表删除
# Base.metadata.drop_all(engine)

表模型

from sqlalchemy import create_engine
import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String,Text,ForeignKey,DateTime,UniqueConstraint,Index
from sqlalchemy.orm import relationship
from flask import Flask


app = Flask(__name__)

app.secret_key = 'asdfg333'
# 执行declarative_base ,得到一个类

Base=declarative_base()

class Hobby(Base):
    """爱好表"""
    __tablename__ ='hobby'
    id=Column(Integer,primary_key=True)
    caption=Column(String(50),default='看书')


class Person(Base):
    """人"""
    __tablename__ ='person'
    id=Column(Integer,perimary_key=True)
    name=Column(String(32),index=True,nullable=True)
    # 关联字段写在多的一方,写在Person中,跟hobby表中id字段做外键关联
    hobby_id=Column(Integer,ForeignKey("hobby.id"))
    # 这里的字段跟数据无关,并不会新增字段,只是用于快速连表操作
    # 基于对象的跨表查询:就需要加上这个字段,取对象person.hobby  person.hobby_id
    #类名,backref 用于反向查询
    hobby=relationship("Hobby",backref='pers')  # 如果有hobby对象,就拿到所有人的hobby.pers

    def __repr__(self):
        return self.name



engine=create_engine("mysql+pymysql://root:root123@127.0.0.1:3306/root_db")
Base.metadata.create_all(engine)

# 把所有的表删除
# Base.metadata.drop_all(engine)

新增和基于对象的查询

# 一对多新增
hobby=Hobby(caption='乒乓球')
session.add(hobby)
person=Person(name='小白')
session.add(person)

person=Person(name='小黑',hobby_id=1)
person=Person(name='小黑',hobby_id=hobby.id)

hobby==session.query(Hobby).filter(Hobby.caption=='篮球').first()


支持按对象的增加方式,必须加relationship,做关联

# 方式一:
hobby=session.query(Hobby).filter(Hobby.caption=='足球').first()
person=Person(name='小红',hobby=hobby)

# 方式二:
hobby=Hobby(caption='羽毛球',hobby=hobby)
session.add_all([person,hobby])
session.commit()


基于对象的跨表查询
# 正向查询
person=session.query(person).filter(Person.name='小白').first()


# 反向查询
hobby=session.query(Hobby).filter(Hobby.id==1).first()

多对多连表查洵

# 表模型  多对多会使用到中间表,所以创建中间表
# 多对多

# 中间表  手动创建
class Boy2Girl(Base):
    __tablename__ = 'boy2girl'
    id = Column(Integer, primary_key=True, autoincrement=True)
    girl_id = Column(Integer, ForeignKey('girl.id'))
    boy_id = Column(Integer, ForeignKey('boy.id'))


class Girl(Base):
    __tablename__ = 'girl'
    id = Column(Integer, primary_key=True)
    name = Column(String(64), unique=True, nullable=False)

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name


class Boy(Base):
    __tablename__ = 'boy'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(64), unique=True, nullable=False)

# 与生成 的表结构无关,仅仅是用于查询方便,放在那个表单中都可以,relationshi方便快速查询,写了这字段,相当于是django的ManyToMany,快速使用基于对象的跨表的查询
girls=relationship('Girl',secondary='boy2girl',backref='boys')

def __str__(self):
    return self.name

def __repr__(self):
    return self.name

engine=create_engine("mysql+pymysql://root:root123@127.0.0.1:3306/root_db")
# 把表同步到数据库中(把被Base管理的所有表,都创建到数据库)
Base.metadata.create_all(engine)

增加和基于对象化的跨表查询

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
from models2 import Girl, Boy, Boy2Girl

engine = create_engine("mysql+pymysql://root@127.0.0.1:3306/aaa")
Session = sessionmaker(bind=engine)
session = scoped_session(Session)

# 新增
# 1 笨办法新增
# girl=Girl(name='刘亦菲')
# boy=Boy(name='彭于晏')
# session.add_all([girl,boy])
# session.add(Boy2Girl(girl_id=1,boy_id=1))
# session.commit()

# 2 使用relationship
# boy = Boy(name='lqz')
# boy.girls = [Girl(name='迪丽热巴'), Girl(name='景田')]
# session.add(boy)
# session.commit()


# 基于对象的跨表查询
# 正向
# boy = session.query(Boy).filter(Boy.id==2).first()
# print(boy.girls)

# 反向
# girl = session.query(Girl).filter(Girl.id==2).first()
# print(girl.boys)
# 如果没有relationship,纯自己操作

连表查询

### 关联关系,基于连表的跨表查询
from models1 import Person,Hobby
# 链表操作
# select * from person,hobby where person.hobby_id=hobby.id;
# res = session.query(Person, Hobby).filter(Person.hobby_id == Hobby.id).all()

# 自己连表查询
# join表,默认是inner join,自动按外键关联
# select * from Person inner join Hobby on Person.hobby_id=Hobby.id;
# res = session.query(Person).join(Hobby).all()

#isouter=True 外连,表示Person left join Favor,没有右连接,反过来即可
# select * from Person left join Hobby on Person.hobby_id=Hobby.id;
# res = session.query(Person).join(Hobby, isouter=True).all()
# 没有right join,通过这个实现
# res = session.query(Hobby).join(Person, isouter=True).all()

# # 自己指定on条件(连表条件),第二个参数,支持on多个条件,用and_,同上
# select * from Person left join Hobby on Person.id=Hobby.id;
# res = session.query(Person).join(Hobby, Person.hobby_id == Hobby.id, isouter=True) #  sql本身有问题,只是给你讲, 自己指定链接字段
# 右链接
# print(res)



# 多对多关系连表
# 多对多关系,基于链表的跨表查
#方式一:直接连
res = session.query(Boy, Girl,Boy2Girl).filter(Boy.id == Boy2Girl.boy_id,Girl.id == Boy2Girl.girl_id).all()
# 方式二:join连
res = session.query(Boy).join(Boy2Girl).join(Girl).filter(Person.id>=2).all()

flask-sqlalchemy使用

# 它集成到flask中,直接使用sqlalchemy
# 有个第三方flask-sqlalchemy,帮助我们快速的继承到flask中

# 使用flask-sqlalchemy集成
1.导入flask-sqlalchemy
from flask-sqlalchemy import SQLAlchemy
2.实例化的到一个对象
	db=sqlAlchemy()
    
3.将db注册到app中
	db.init_app(app)
    
4.视图函数中使用session  # 使用的是线程安全的那个
	全局的db.session 
    
5.models.py 中继承Model
	db.Model
6.直接写字段
	username=db.Column(db.String(80),unique=True,nullable=False)
    
7.在配置文件中加入
    SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:root123@127.0.0.1:3306/root_db"
    SQLALCHEMY_POOL_SIZE = 5
    SQLALCHEMY_POOL_TIMEOUT = 30
    SQLALCHEMY_POOL_RECYCLE = -1
    # 追踪对象的修改并且发送信号
    SQLALCHEMY_TRACK_MODIFICATIONS = False

flask-migrate的使用

  • 在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库。最直接的方式就是删除旧表,但这样会丢失数据。

    更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中。在Flask中可以使用Flask-Migrate扩展,来实现数据迁移。

# 在原生的sqlalchemy,是不支持修改表的
在flask-migrate 是可以实现类似于django的
python manage.py makegrations # 记录
python manage.py mirgate  # 数据同步到数据库中

# 使用步骤
$ 安装的flask 是2.2.2  flask-script:2.0.3

1.安装。,依赖于 flask-script 
	pip install flask-migrate==2.7.0
    
2.在app所在的py文件中
	from flask-script import Manager
    from flask_migrate import Migrate,MigrateCommand
    Manager=Manager(app)
    Migrate(app,db)
    Manager.add_Command('db',MigrateCommand)
    manager.run() # 以后可以直接使用python manage.py runserver 来启
	动项目
    
    
3.第一次执行
	# 会生成一个migrations文件夹,里面以后不要动,里面记录迁移的编号
    python manage.py db init 
  
4.以后在models.py 中写表,加字段,删字段,改参数
5.只需要执行
python manage.py db migrate  # 记录
python manage.py db upgrade  # 同步到数据库
posted @ 2023-04-12 16:01  亓官扶苏  阅读(13)  评论(0编辑  收藏  举报