ORM框架
1 面向对象
函数编程是有很多局部变量和函数的, 这样会有很多重复
形成的面向对象思想
面向对象思想的使用条件:
当一类函数共用同样的参数的时候, 面向对象会把数据和逻辑组合在一起
常用的面向对象特殊方法
__init__(): 初始化
__call__(): 对象后面加括号执行
__dict__: 含有的数据
对象[key]: __getitem__(self, key)
对象[key] = 值: __setitem__(self, key, value)
del 对象[key]: __delitem__(self)
2 ORM框架
主流的Python中的ORM框架是: SQLAlchemy
作用:
1) 提供简单的规则
2) 自动转换成SQL语句
分类
1) db first: [手动]数据库+表 -->ORM --> [自动]类
2) code first: [手动]数据库+类 -->ORM --> [自动]表
3 SQLAlchemy的使用
3.1 创建数据库
1) 新建连接
from sqlalchemy import create_engine
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5)
分别是格式是: 数据库类型+连接API://用户名:密码@IP地址/数据库名max_cverflow表示最大连接数, 是通过ConnectionPooling来实现连接池的
2) 创建表对应的类
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, UniqueConstraint, Index
Base = declarative_base()
class UserType(Base):
__tablename__ = 'usertype'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(32), nullable=True, default='NoName', index=True)
class Users(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(32), nullable=True, default='NoName', index=True)
extra = Column(String(16), unique=True)
user_type_id = Column(Integer, ForeignKey("usertype.id"))
__table_args__ = (
UniqueConstraint('id', 'name', name='uix_id_name'),
Index('ix_id_name', 'name', 'extra'),
)
其中要保证, 该类继承自declarative_base()
创建以列是使用Conlum, 里面可以传入数据类型和约束条件primary_key, autoincrement等
可以创建外键, 注意外键的写法是首字母F大写, 和别的不一样
特殊变量__tablename__记录表名
特殊变量__table_args__记录表级约束条件, 其中的诸如Index()有多个参数, 第一个参数默认是约束条件的名字, 如果不放在第一个参数上, 在后面就需要指定name=
3) 创建或者删除数据库
Base.metadata.create_all(engine)
Base.metadata.drop_all(engine)
注意创建或者删除不是随意的, 是找到继承自Base的类进行相应的创建
3.2 记录的操作
1) 基本框架
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/orm", max_overflow=5)
Session = sessionmaker(bind=engine)
session = Session()
# 数据库操作
session.commit()
session.close()
通过bind创建一个会话, 通过这个会话得到一个会话对象, 经过一系列的操作之后, 需要提交并关闭会话
2) 插入数据
obj1 = UserType(title='普通用户')
session.add(obj1)
objs =[
UserType(title='超级用户'),
UserType(title='白金用户'),
UserType(title='黑金用户'),
]
session.add_all(objs)
有两种插入数据的方式, 单条插入的时候用add()方法插入一个表对象; 多条插入的时候是使用add_all()传入一个list, 里面的元素是一个个表对象
3) 生成SQL语句
可以通过query()函数来生成一个SQL语句
里面的参数传入数据, 若是一个表类名, 表示查询整个表
session.query(UserType)
#SELECT usertype.id AS usertype_id, usertype.title AS usertype_title FROM usertype
可以在后面加上函数all()来执行得到结果
session.query(UserType).all()
# [<__main__.UserType object at 0x000000000383D630>,
# <__main__.UserType object at 0x000000000383D668>,
# <__main__.UserType object at 0x000000000383D6D8>]
可以遍历结果得到每一行, 可以用数组的方式获得值, 亦可以用.的方法.属性
user_type_list = session.query(UserType).all()
for row in user_type_list:
print(row[0],row.title)
使用filter()可以增加查询条件, 相当于where
session.query(UserType.id,UserType.title).filter(UserType.id > 2)
删除数据需要先使用query查询到在使用delete()
session.query(UserType.id,UserType.title).filter(UserType.id > 2).delete()
修改数据的使用update()
session.query(UserType.id,UserType.title).filter(UserType.id > 0).update({"title" : "黑金"})
session.query(UserType.id,UserType.title).filter(UserType.id > 0).update({UserType.title: UserType.title + "x"}, synchronize_session=False)
session.query(UserType.id,UserType.title).filter(UserType.id > 0).update({"num": Users.num + 1}, synchronize_session="evaluate")
其中synchronize_session=False与字符串处理的时候联合使用的
synchronize_session="evaluate"是处理数字类型的时候联合使用的
3.3 进阶的SQL语句
1) 条件
ret = session.query(Users).filter_by(name='alex').all()
ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all()
# filter中的条件用逗号隔开, 默认是AND
ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all()
ret = session.query(Users).filter(Users.id.in_([1,3,4])).all()
ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all()
# not in的写法
ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all()
# 之前默认的条件叠加的and, 可以把条件该为or, 需要导入包
from sqlalchemy import and_, or_
ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all()
ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all()
ret = session.query(Users).filter(
or_(
Users.id < 2,
and_(Users.name == 'eric', Users.id > 3),
Users.extra != ""
)).all()
# 谁的方法, 里面的值就是按照什么类型拼接
2) 通配符
ret = session.query(Users).filter(Users.name.like('e%')).all()
ret = session.query(Users).filter(~Users.name.like('e%')).all()
3) limit限制
ret = session.query(Users)[1:2]
4) 排序
ret = session.query(Users).order_by(Users.name.desc()).all()
ret = session.query(Users).order_by(Users.name.desc(),Users.id.asc()).all()
5) 分组
ret = session.query(Users).group_by(Users.extra).all()
from sqlalchemy.sql import func
# 导入func才能够使用聚合函数
ret = session.query(
func.max(Users.id),
func.sum(Users.id),
func.min(Users.id)).group_by(Users.name).all()
# 可以使用having语句
ret = session.query(
func.max(Users.id),
func.sum(Users.id),
func.min(Users.id)).group_by(Users.name).having(func.min(Users.id)>2).all()
6) 联结
# 笛卡尔积 相当于:select * from user,usertype;
ret = session.query(Users,UserType)
# 內联结 相当于:select * from user,usertype whre user.usertype_id = usertype.id
ret = session.query(Users,UserType).filter(Users.usertype_id==UserType.id)
# 內联结, 默认会查找外键, 通过外键来联结
ret = session.query(Users).join(UserType)
# 左联结
ret = session.query(Users).join(UserType,isouter=True)
7) 组合
q1 = session.query(Users.name).filter(Users.id >2)
q2 = session.query(Favor.caption).filter(Favor.nid <2)
ret = q1.union(q2).all()
q1 = session.query(Users.name).filter(Users.id >2)
q2 = session.query(Favor.caption).filter(Favor.nid <2)
ret = q1.union_all(q2).all()
8) 子查询
# 子查询 等同效果:select * from (select * from tb) as B
q1 = session.query(UserType).filter(UserType.id >0).subquery()
ret = session.query(q1).all()
9) 记录子查询
# 查询语句 等效于:
# select
# id ,
# (select * from users where users.user_type_id=usertype.id)
# from usertype;
ret = session.query(UserType.id,session.query(Users).filter(Users.user_type_id==UserType.id).as_scalar())
如果此时用子查询subquery()会得到一个笛卡尔积, 因为subquery()会返回一个临时表
使用as_scalar()相当于得到一个相应的查询语句, 并且用()包裹起来
3.4 关系表
数据库中常常用到有外键的表的联结操作
在SQLAlchemy中有一个便捷的操作可以使得不用手动联结也能在查询中使用
也就是使用relationship
在带有外键的类中添加
关系名A = relationship("关联的表的类名",backref='回调名B')
这样就可以在查询该表的时候获得关系名A, 通过关系名A点的方式得到对应的关联表的数据
同时查询对应的关联表, 就可以得到回调名B, 通过回调名B点的方式得到该表的数据
人若有恒 无所不成