pip install sqlalchemy
Engine | 框架的引擎 |
---|---|
Connection Pooling | 数据库连接池 |
Dialect | 选择连接数据库的DB API类 |
Schema/Types | 架构和类型 |
SQL Exprression Language | SQL表达式语言 |
SQLAlchemy本身无法操作数据库,其必须依赖pymysql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API从而实现对数据库的操作
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine
"""
比pymysql优秀在哪里
自己维护了一个池
"""
# 第一步 生成一个engine对象
engine = create_engine(
'mysql+pymysql://root:123456@127.0.0.1:3306/django?charset=utf8',
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的事件,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第二步:创建连接(执行原生sql)
conn = engine.raw_connection()
# 第三步:获取游标对象
cursor = conn.cursor()
# 第四步:具体操作
cursor.execute('select * from app01_user')
res = cursor.fetchall()
print(res)
只能通过base创建表,不能创建库,不能修改表
以下只为创建实例使用,不与下文增删改查关联
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()
# 创建一个个的类,继承Base
class User(Base):
__tablename__ = 'users' # 数据库表名称
id = Column(Integer, primary_key=True) # id 主键
name = Column(String(32), index=True, nullable=False) # name 索引,不为空
email = Column(String(32), unique=True) # unique唯一
ctime = Column(DateTime, default=datetime.datetime.now)
extra = Column(Text, nullable=True)
# 类似于django中的Meta
__table_args__ = (
UniqueConstraint('id', 'name', name='uix_id_name'), # 联合唯一
Index('ix_id_name', 'name', 'email') # 索引
)
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
# 创建表
# 创建的表都是通过base管理的表
def create_table():
# 创建对象,通过engine_create创建出表
engine = create_engine(
'mysql+pymysql://root:123456@127.0.0.1:3306/test?charset=utf8',
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的事件,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
Base.metadata.create_all(engine)
# 删除表
def drop_table():
engine = create_engine(
'mysql+pymysql://root:123456@127.0.0.1:3306/test?charset=utf8',
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的事件,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 通过engine删除所有的表(通过Base管理的表)
Base.metadata.drop_all(engine)
if __name__ == '__main__':
# 创建表
create_table()
# 删除表
# drop_table()
user表创建
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
# 制造了一个类,作为所有模型类的基类
Base = declarative_base()
# 创建一个个的类(继承谁?字段怎么写)
class Name(Base):
__tablename__ = 'name' # 数据库表名称
id = Column(Integer, primary_key=True) # id 主键
name = Column(String(32), index=True, nullable=False) # name 索引,不为空
表创建(通过复制5.2中的内容执行)完成后执行以下操作
基本操作
from models import Name
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
# 第一步 生成一个engine对象
engine = create_engine(
'mysql+pymysql://root:123456@127.0.0.1:3306/test?charset=utf8',
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的事件,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第二步 制造一个session类
Session = sessionmaker(bind=engine)
# 第三步 得到一个session对象
session = Session()
# 第四步 创建一个对象
obj1 = Name(name='zyc')
# 第五步 把对象放进session对象中
session.add(obj1)
# 第六步 提交
session.commit()
session.close()
from models import User
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy import create_engine
# 第一步 生成一个engine对象
engine = create_engine(
'mysql+pymysql://root:123456@127.0.0.1:3306/test?charset=utf8',
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的事件,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第二步 制造一个session类
Session = sessionmaker(bind=engine)
# 第三步 得到一个session对象(线程安全的session对象)
'''
不再使用Session对象,通过scoped_session将Session传入,
内部实现通过threading.local()实现,从而保证了数据的安全。
'''
session = scoped_session(Session)
# 第四步 创建一个对象
obj1 = User(name='lqz')
# 第五步 把对象放进session对象中
session.add(obj1)
# 第六步 提交
session.commit()
session.close()
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
# 制造了一个类,作为所有模型类的基类
Base = declarative_base()
# 创建一个个的类(继承谁?字段怎么写)
class User(Base):
__tablename__ = 'users' # 数据库表名称
id = Column(Integer, primary_key=True) # id 主键
name = Column(String(32), index=True, nullable=False) # name 索引,不为空
def __repr__(self):
return self.name
表创建(通过复制5.2中的内容执行)完成后执行以下操作
ps:以下内容为增删改查操作的时候需要的session对象创建
from models import User
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(
'mysql+pymysql://root:123456@127.0.0.1:3306/test?charset=utf8',
echo=True, # 打印log信息
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的事件,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
Session = sessionmaker(bind=engine)
session = Session()
# your code write here
# 并不是真正关闭数据库,而是将连接关闭,放回池中
session.close()
新增单条数据
obj = User(name='张三')
session.add(obj)
session.commit()
新增多条数据
obj1 = User(name='李四')
obj2 = User(name='王五')
obj3 = User(name='马六')
session.add_all([obj1, obj2, obj3])
session.commit()
'''
filter 过滤
filter_by 过滤
all 返回全部符合条件的结果
first 返回全部结果中的第一个结果
filter和filter_by的区别?
filter:用类名.属性名,比较用==,支持and,or和in等
filter_by:直接用属性名,比较用=
最重要的区别是filter不支持组合查询,只能连续调用filter来变相实现。
而filter_by的参数是**kwargs,直接支持组合查询。
'''
ret = session.query(User).filter(User.id == 4).all() # list
ret = session.query(User).filter_by(id=4).all() # list
ret = session.query(User).filter(User.id <= 4).all() # list
ret = session.query(User).filter(User.id >= 4).first() # object
print(ret)
# 原生sql查询
res = session.query(User).from_statement(text("SELECT * FROM users where name=:name")).params(name='zzz999').first()
print(res.id)
print(res.name)
ret = session.query(User).filter(User.id==10).delete()
session.commit()
# 固定用法 synchronize_session为False时做拼接,为evaluate时,数字相加
session.query(User).filter(User.id > 0).update({User.name: User.name + '999'}, synchronize_session=False)
session.query(User).filter(User.id > 0).update({User.id: User.id + 1}, synchronize_session='evaluate')
ret = session.query(User).filter_by(id=11).update({User.name: 'ccc'})
ret = session.query(User).filter(User.id == 11).update({User.name: 'xxx'})
session.commit()
PS:操作orm时,增、删、改都需要commit操作,数据才会进行同步。
res = session.query(User).filter(User.id >= 1, User.name == 'lqz').all()
print(res)
res = session.query(User).filter(User.id.between(0, 3), User.name == 'lqz').all()
print(res)
res = session.query(User).filter(User.id.in_([1, 3, 4]), User.name == 'lqz').all()
print(res)
res = session.query(User.name, User.id).filter(User.id.in_(session.query(User.id).filter_by(name='lqz'))).all()
print(res)
from sqlalchemy import and_, or_
res = session.query(User).filter(and_(User.id >= 2, User.name == 'alex')).all()
res = session.query(User).filter(or_(User.id > 10, User.name == 'alex')).all()
res = session.query(User).filter(~or_(User.id > 10, User.name == 'alex')).all()
print(res)
# 查询用户名字以a开头的用户
res = session.query(User).filter(User.name.like('a%')).all()
# 查询用户名字不以a开头的用户
res = session.query(User.id).filter(~User.name.like('a%')).all()
print(res)
res = session.query(User)[1:2]
print(res)
# 排序,desc降序,asc升序
res = session.query(User.id, User.name).order_by(User.id.desc()).all()
res = session.query(User.id, User.name).order_by(User.id.asc()).all()
res = session.query(User.id, User.name).order_by(User.name.desc(), User.id.asc()).all()
print(res)
from sqlalchemy.sql import func
res = session.query(User).group_by(User.name).all()
res = session.query(func.max(User.id)).group_by(User.name).all()
res = session.query(func.min(User.id)).group_by(User.name).all()
res = session.query(func.sum(User.id)).group_by(User.name).all()
res = session.query(func.count(User.id)).group_by(User.name).all()
res = session.query(func.avg(User.id)).group_by(User.name).all()
print(res)
res = session.query(func.min(User.id), User.name).group_by(User.name).having(func.min(User.id) > 2).all()
print(res)
# UNION操作符用于合并两个或更多的select语句的结果集
# union 并集去重
# union all 并集 不去重
# union
from models import User
q1 = session.query(User.id).filter(User.id > 1)
q2 = session.query(User.id).filter(User.id < 3)
res = q1.union(q2).all()
print(res)
#union all
q1 = session.query(User.id).filter(User.id > 1)
q2 = session.query(User.id).filter(User.id < 3)
res = q1.union_all(q2).all()
print(res)
session.execute('insert into boy(hostname) values (:value)', params={'value': '马冬梅'})
session.commit()
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import relationship
Base = declarative_base()
class Hobby(Base):
__tablename__ = 'hobby'
id = Column(Integer, primary_key=True)
caption = Column(String(50), default='篮球')
class Person(Base):
__tablename__ = 'person'
nid = Column(Integer, primary_key=True)
name = Column(String(32), index=True, nullable=True)
hobby_id = Column(Integer, ForeignKey('hobby.id'))
# 跟数据库无关,不会新增字段,只用于快速链表操作
# 类名,backref用于反向查询
hobby = relationship('Hobby', backref='pers')
PS:表创建(通过复制5.2中的内容执行)完成后执行以下操作
h_obj = Hobby(caption='打球')
p_obj = Person(name='王五', hobby_id='2')
session.add_all([h_obj, p_obj])
session.commit()
# 默认传入对象不支持,需要在表中添加relationship字段
p = Person(name='马六', hobby=Hobby(caption='就这'))
session.add(p)
session.commit()
# 等同于
p = Person(name='马六2')
p.hobby = Hobby(caption='就这2')
session.add(p)
session.commit()
hobby = Hobby(caption='做饭')
hobby.pers = [Person(name='张三啊')] # 可以传入多个对象,列表中逗号隔开
session.add(hobby)
session.commit()
# 正向查询
p = session.query(Person).filter_by(name='张三').first()
print(p)
print(p.hobby.caption)
# 反向查询
h = session.query(Hobby).filter_by(caption='做饭').first()
print(h)
print(h.pers[0].name)
'''
join连表默认通过外键连接
isouter默认为False,表示inner join
isouter = True表示左外连接,表示Person left outer join Hobby
ps:写完查询后,不添加.all或者.first就可以查看原生sql语句,例如
session.query(Hobby).filter_by(caption='做饭')
打印出来就是原生sql
'''
# 左外连接
res = session.query(Person).join(Hobby, isouter=True).filter(Hobby.caption == '做饭').first()
res = session.query(Person).join(Hobby, isouter=True).filter_by(caption='做饭').first() # 和上边相同
print(res)
# 原生sql
'''SELECT * FROM person LEFT OUTER JOIN hobby ON hobby.id = person.hobby_id WHERE hobby.caption = "做饭"'''
# 内连接
res = session.query(Person, Hobby).filter(Person.hobby_id == Hobby.id).all()
print(res)
res = session.query(Person).join(Hobby).all()
print(res)
# 指定连表字段(基本不用)
res = session.query(Person).join(Hobby, Person.nid == Hobby.id, isouter=True).all()
print(res)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, ForeignKey, Integer
from sqlalchemy.orm import relationship
Base = declarative_base()
class Boy(Base):
__tablename__ = 'boy'
id = Column(Integer, primary_key=True, autoincrement=True)
hostname = Column(String(64), unique=True, nullable=False)
# 与生成表结构无关,仅用于查询方便,放在哪个表中都可以
# secondary通过哪个表监理关联,跟django中的through一模一样
girls = relationship('Girl', secondary='boy2girl', backref='boys')
class Girl(Base):
__tablename__ = 'girl'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(64), unique=True, nullable=False)
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'))
PS:表创建(通过复制5.2中的内容执行)完成后执行以下操作
session.add_all([
Boy(hostname='小明'),
Boy(hostname='小刚'),
Girl(name='小红'),
Girl(name='小翠'),
])
session.commit()
session.add_all([
Boy2Girl(girl_id=1, boy_id=1),
Boy2Girl(girl_id=2, boy_id=1),
Boy2Girl(girl_id=2, boy_id=1)
])
session.commit()
girl = Girl(name='小青')
girl.boys = [Boy(hostname='小强'), Boy(hostname='小丁')]
session.add(girl)
session.commit()
boy = Boy(hostname='小布')
boy.girls = [Girl(name='小白'), Girl(name='小粉')]
session.add(boy)
session.commit()
# 查询和小白认识的所有男生
girl = session.query(Girl).filter_by(name='小白').first()
print(girl.boys)
# 查询和小明认识的所有女生
boy = session.query(Boy).filter_by(hostname='小明').first()
print(boy.girls)
res = session.query(Girl.name).filter(Boy.id == Boy2Girl.boy_id, Girl.id == Boy2Girl.girl_id,
Boy.hostname == '小丁').first()
print(res)
res = session.query(Girl.id, Girl.name).join(Boy2Girl).join(Boy).filter(Boy.hostname == '小明').all()
print(res)
res = session.query(Boy.hostname).join(Boy2Girl).join(Girl).filter(Girl.name == '小红').all()
print(res)
欢迎补充