SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:
MySQL-Python mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> pymysql mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] MySQL-Connector mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> cx_Oracle oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
一、底层处理
使用 Engine/ConnectionPooling/Dialect 进行数据库操作,Engine使用ConnectionPooling连接数据库,然后再通过Dialect执行SQL语句。
#!/usr/bin/env python # -*- coding:utf-8 -*- from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5) # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES ('1.1.1.22', 3)" # ) # 新插入行自增ID # cur.lastrowid # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES(%s, %s)",[('1.1.1.22', 3),('1.1.1.221', 3),] # ) # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES (%(host)s, %(color_id)s)", # host='1.1.1.99', color_id=3 # ) # 执行SQL # cur = engine.execute('select * from hosts') # 获取第一行数据 # cur.fetchone() # 获取第n行数据 # cur.fetchmany(3) # 获取所有数据 # cur.fetchall()
二、ORM功能使用
ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。 正确使用ORM的前提是了解关系数据库的原理。 ORM就是把数据库表的行与相应的对象建立关联,互相转换。 由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应地, ORM框架也可以提供两个对象之间的一对多、多对多等功能。
1 创建表
#coding:utf8 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String from sqlalchemy.orm import sessionmaker print(sqlalchemy.__version__) engine = create_engine('sqlite:///dbyuan111.db', echo=True)#1 连接数据库 Base = declarative_base()#2 生成一个SQLORM基类 class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) fullname = Column(String) password = Column(String) def __repr__(self): return "<User(name='%s', fullname='%s', password='%s')>" % ( self.name, self.fullname, self.password) Base.metadata.create_all(engine) #3 创建所有表结构 ed_user = User(name='xiaoyu', fullname='Xiaoyu Liu', password='123') # print(ed_user) #3 这两行触发sessionmaker类下的__call__方法,return得到 Session实例,赋给变量session,所以session可以调用Session类下的add,add_all等方法 MySession = sessionmaker(bind=engine) session = MySession() # session.add(ed_user) # our_user = session.query(User).filter_by(name='ed').first() # SELECT * FROM users WHERE name="ed" LIMIT 1; # session.add_all([ # User(name='alex', fullname='Alex Li', password='456'), # User(name='alex', fullname='Alex old', password='789'), # User(name='peiqi', fullname='Peiqi Wu', password='sxsxsx')]) # session.commit() #print(">>>",session.query(User).filter_by(name='ed').first()) #print(session.query(User).all()) #order_by前不加all() # for row in session.query(User).order_by(User.id): # print('<<',row) # for row in session.query(User).filter(User.name.in_(['alex', 'wendy', 'jack'])):#这里的名字是完全匹配 # print(row) # for row in session.query(User).filter(~User.name.in_(['ed', 'wendy', 'jack'])): # print(row) #print(session.query(User).filter(User.name == 'ed').count()) #from sqlalchemy import and_, or_ # for row in session.query(User).filter(and_(User.name == 'ed', User.fullname == 'Ed Jones')): # print(row) # for row in session.query(User).filter(or_(User.name == 'ed', User.name == 'wendy')): # print(row) 单表
# #coding:utf8 # # import sqlalchemy # from sqlalchemy import create_engine # from sqlalchemy.ext.declarative import declarative_base # from sqlalchemy import Column, Integer, String,ForeignKey # from sqlalchemy.orm import sessionmaker,relationship # # # engine = create_engine('sqlite:///dbyuan2.db', echo=True) # # Base = declarative_base() # #多对多:创建第三张表 # class Author2Book(Base): # __tablename__='author2book' # # nid=Column(Integer,primary_key=True) # author_id=Column(Integer,ForeignKey("author.id")) # book_id=Column(Integer,ForeignKey("book.id")) # # # class Publisher(Base): # __tablename__ = 'publisher' # #id = Column(Integer, primary_key=True)里的数据类型一定写整型(Integer) # id = Column(Integer, primary_key=True) # name = Column(String(20)) # city = Column(String(20)) # country = Column(String(20)) # # # def __str__(self): # return self.name # # class Author(Base): # __tablename__ = 'author' # id = Column(Integer, primary_key=True) # name = Column(String(20)) # # def __str__(self): # return self.name # # class AuthorDetail(Base): # __tablename__ = 'author_detail' # # id = Column(Integer, primary_key=True) # sex = Column(String(20),default='male') # email =Column(String(20),default='123@qq.com') # address = Column(String(20),default='beijing') # birthday =Column(String(20)) # author = Column(String(20),ForeignKey('author.id'),unique=True)#一对一 # # class Book(Base): # __tablename__ = 'book' # # id = Column(Integer, primary_key=True) # title = Column(String(20)) # publisher_id = Column(String(20),ForeignKey('publisher.id'))#一对多 # publication_date = Column(String(20)) # price=Column(String(20)) # # def __str__(self): # return self.title # # # # # Base.metadata.create_all(engine) # # Session = sessionmaker(bind=engine) # session = Session() # # # b1= Book(title='PHP',publisher_id=1,publication_date='2016-8-24',price=100) # b2= Book(title='python',publisher_id=3,publication_date='2017-8-24',price=210) # b3= Book(title='java',publisher_id=2,publication_date='2018-8-24',price=90) # # a1=Author(name='alex') # a2=Author(name='alvin') # # ad1=AuthorDetail(birthday='1980-2-16',author=1) # ad2=AuthorDetail(birthday='1990-3-16',author=1) # # # p1=Publisher(name='北大出版社',city='北京',country='中国') # p2=Publisher(name='河大出版社',city='保定',country='中国') # p3=Publisher(name='中国机械出版社',city='北京',country='中国') # # ab1=Author2Book(author_id=1,book_id=1) # ab2=Author2Book(author_id=1,book_id=2) # ab3=Author2Book(author_id=2,book_id=2) # # # session.add_all([a1,a2,ad1,ad2,b1,b2,b3,p1,p2,p3,ab1,ab2,ab3]) # session.commit() #################################################### #很明显,这种建立表关系的方式不够直接和简单. #coding:utf8 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String,ForeignKey from sqlalchemy.orm import sessionmaker,relationship engine = create_engine('sqlite:///dbyuan242246.db', echo=True) Base = declarative_base() #多对多:创建第三张表 class Author2Book(Base): __tablename__='author2book' nid=Column(Integer,primary_key=True) author_id=Column(Integer,ForeignKey("author.id")) book_id=Column(Integer,ForeignKey("book.id")) class Publisher(Base): __tablename__ = 'publisher' #id = Column(Integer, primary_key=True)里的数据类型一定写整型(Integer) id = Column(Integer, primary_key=True) name = Column(String(20)) city = Column(String(20)) country = Column(String(20)) def __str__(self): return self.name class Author(Base): __tablename__ = 'author' id = Column(Integer, primary_key=True) name = Column(String(20)) book_obj_list=relationship('Book',secondary=Author2Book.__table__,backref='author_obj_list')#多对多的relationship如是写,有一个secondary def __str__(self): return self.name class AuthorDetail(Base): __tablename__ = 'author_detail' id = Column(Integer, primary_key=True) sex = Column(String(20),default='male') email =Column(String(20),default='123@qq.com') address = Column(String(20),default='beijing') birthday =Column(String(20)) author = Column(String(20),ForeignKey('author.id'),unique=True)#一对一 class Book(Base): __tablename__ = 'book' id = Column(Integer, primary_key=True) title = Column(String(20)) publisher_id = Column(String(20),ForeignKey('publisher.id'))#一对多 publisher_obj_list=relationship('Publisher',backref='book_obj_list')#一对多的relationship如是写 publication_date = Column(String(20)) price=Column(String(20)) def __str__(self): return self.title Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() #publisher_id不用加上啦 b1= Book(title='PHP',publication_date='2016-8-24',price=100) b2= Book(title='python',publication_date='2017-8-24',price=210) b3= Book(title='java',publication_date='2018-8-24',price=90) a1=Author(name='alex') a2=Author(name='alvin') ad1=AuthorDetail(birthday='1980-2-16',author=1) ad2=AuthorDetail(birthday='1990-3-16',author=2) p1=Publisher(name='北大出版社',city='北京',country='中国') p2=Publisher(name='河大出版社',city='保定',country='中国') p3=Publisher(name='中国机械出版社',city='北京',country='中国') # ab1=Author2Book(author_id=1,book_id=1) # ab2=Author2Book(author_id=1,book_id=2) # ab3=Author2Book(author_id=2,book_id=2) #第三张表就不用插入数据了 #建立多对多的关系,增加关系用append:b1.author_obj_list.append([a1,a2]) b1.author_obj_list=[a1,a2] b2.author_obj_list=[a1,a2] b1.publisher_obj_list=p1 # b1.publisher_obj_list=[p1,p2,p3]这样会报错,因为一对多的关系,b1.publisher_obj_list不可能绑定多个对象,反过来可以,如下 p1.book_obj_list=[b1,b2,b3] ''' 大家思考:b1.publisher_obj_list=p1与p1.book_obj_list=b1效果相同吗? 其实是一样的,举个例子:书法协会作为一个团体招人,alex也想进入该协会,两个动作都可以完成这件事: 书法协会作为主体把alex招了进来 alex作为主体加入了该组织 ''' ''' 注意点: ret = session.query(Users).all() 有all().first()等,ret是对象列表;没有,则是sql语句 关联查询 r = session.query(Book.title,Publisher.name).join(Publisher).all() r = session.query(Author2Book).join(Author).all() ''' session.add_all([a1,a2,ad1,ad2,b1,b2,b3,p1,p2,p3]) session.commit() 关系表
2 操作表
obj = Users(name="alex0", extra='sb') session.add(obj) session.add_all([ Users(name="alex1", extra='sb'), Users(name="alex2", extra='sb'), ]) session.commit() 增
session.query(Users).filter(Users.id > 2).delete() session.commit()
session.query(Users).filter(Users.id > 2).update({"name" : "099"}) session.query(Users).filter(Users.id > 2).update({Users.name: Users.name + "099"}, synchronize_session=False) session.query(Users).filter(Users.id > 2).update({"num": Users.num + 1}, synchronize_session="evaluate") session.commit()
ret = session.query(Users).all() ret = session.query(Users.name, Users.extra).all() ret = session.query(Users).filter_by(name='alex').all() ret = session.query(Users).filter_by(name='alex').first()
# 条件 ret = session.query(Users).filter_by(name='alex').all() ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all() 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() ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all() 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() # 通配符 ret = session.query(Users).filter(Users.name.like('e%')).all() ret = session.query(Users).filter(~Users.name.like('e%')).all() # 限制 ret = session.query(Users)[1:2] # 排序 ret = session.query(Users).order_by(Users.name.desc()).all() ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all() # 分组 from sqlalchemy.sql import func ret = session.query(Users).group_by(Users.extra).all() ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).all() 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() # 连表 ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all() ret = session.query(Person).join(Favor).all() ret = session.query(Person).join(Favor, isouter=True).all() # 组合 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() 其它