一、ORM 框架简介
对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,
关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。
内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,
主要实现程序对象到关系数据库数据的映射。简单的说:ORM相当于中继数据,操作数据、
1.ORM方法论基于三个核心原则:
简单性:以最基本的形式建模数据。
传达性:数据库结构被任何人都能理解的语言文档化。
精确性:基于数据模型创建正确标准化了的结构。
面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,
对象关系映射技术应运而生。O/R中字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,
我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。
当开发一个应用程序的时候(不使用O/R Mapping),可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。在DAL中写了很多的方法来读取对象数据,
改变状态对象等等任务。而这些代码写起来总是重复的。如果开你最近的程序,看看DAL代码,肯定会看到很多近似的通用的模式。我们以保存对象的方法为例,传入一个对象,
为SqlCommand对象添加SqlParameter,把所有属性和对象对应,设置SqlCommand的CommandText属性为存储过程,然后运行SqlCommand。对于每个对象都要重复的写这些代码。
除此之外,还有更好的办法吗?有,引入一个O/R Mapping。实质上,一个O/R Mapping会为你生成DAL。与其自己写DAL代码,不如用O/R Mapping。用O/R Mapping保存,删除,读取对象,
O/R Mapping负责生成SQL,你只需要关心对象就好。对象关系映射成功运用在不同的面向对象持久层产品中,
2. 一般的ORM包括以下四部分:
一个对持久类对象进行CRUD操作的API;
一个语言或API用来规定与类和类属性相关的查询;
一个规定mapping metadata的工具;
一种技术可以让ORM的实现同事务对象一起进行dirty checking, lazy association fetching以及其他的优化操作。
•ORM:及Object-Relational Mapping,把关系数据库的表结构映射到对象上
二、SQLAlchemy介绍
SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
1.安装SQLAlchemy()
pip install SQLAlchemy
2.各种数据库使用SQLALchemy方法
SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作。
MySQL-Python
mysql+mysqldb://:@[:]/
pymysql
mysql+pymysql://:@/[?]
MySQL-Connector
mysql+mysqlconnector://:@[:]/
cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
3.初始化连接
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index,CHAR ,VARCHAR
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine
engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/hjx?charset=utf8", max_overflow=5,echo=True)
参数说明:
max_overflow 设置最大连接数
echo参数为True时,会显示每条执行的SQL语句,可以关闭,
"mysql+pymysql://root:@127.0.0.1:3306/sqlalchemy?charset=utf8" 设定数据库地址、用户名、密码、端口、数据库名称和字符编码
create_engine()返回一个Engine的实例,并且它表示通过数据库语法处理细节的核心接口,在这种情况下,数据库语法将会被解释成python的类方法。
from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/hjx?charset=utf8", max_overflow=5,echo=True) #执行SQL---增 cur = engine.execute( "INSERT INTO equipment (equ_id, equ_sn,supplier,cname,location,ipadd) VALUES ('CQ66','CQMT206','重庆银河','12m³环境箱2','一楼','10.127.1.123')" ) #新插入行自增ID cur.lastrowid #插入多条记录 cur = engine.execute( "INSERT INTO host (ip, name) VALUES(%s, %s)",[('1.1.1.22', 'sever1'),('1.1.1.221', 'server2'),] ) 执行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/Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 所有组件对数据进行操作。根据类创建对象,对象转换成SQL,执行SQL。
1.创建表
a.通过sql语句来创建表:
from sqlalchemy import create_engine
engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/hjx?charset=utf8", max_overflow=5,echo=True)
sql = "create table student(id int not null primary key,name varchar(50),age int,address varchar(100));"
cursor = engine.execute(sql)
b.通过ORM创建表
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine
engine = create_engine("mysql+pymysql://root:[email protected]:3306/t1", max_overflow=5)
Base = declarative_base()
# 创建单表
class Users(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(32))
extra = Column(String(16))
__table_args__ = (
UniqueConstraint('id', 'name', name='uix_id_name'),
Index('ix_id_name', 'name', 'extra'),
)
# 一对多
class Favor(Base):
__tablename__ = 'favor'
nid = Column(Integer, primary_key=True)
caption = Column(String(50), default='red', unique=True)
class Person(Base):
__tablename__ = 'person'
nid = Column(Integer, primary_key=True)
name = Column(String(32), index=True, nullable=True)
favor_id = Column(Integer, ForeignKey("favor.nid"))
# 多对多
class Group(Base):
__tablename__ = 'group'
id = Column(Integer, primary_key=True)
name = Column(String(64), unique=True, nullable=False)
port = Column(Integer, default=22)
class Server(Base):
__tablename__ = 'server'
id = Column(Integer, primary_key=True, autoincrement=True)
hostname = Column(String(64), unique=True, nullable=False)
class ServerToGroup(Base):
__tablename__ = 'servertogroup'
nid = Column(Integer, primary_key=True, autoincrement=True)
server_id = Column(Integer, ForeignKey('server.id'))
group_id = Column(Integer, ForeignKey('group.id'))
def init_db():
Base.metadata.create_all(engine)
def drop_db():
Base.metadata.drop_all(engine)
init_db() #创建表
drop_db() #删除表
2.操作表
#导入相关模块 from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index,CHAR ,VARCHAR from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/test?charset=utf8", max_overflow=5) Base = declarative_base() #创建数据表 type class Type(Base): __tablename__ = 'type' tid = Column(Integer,primary_key=True,autoincrement=True) tname = Column(VARCHAR(25),nullable=False,unique=True) #创建数据表 host class Host(Base): __tablename__ = 'host' hid = Column(Integer,primary_key=True) hostname = Column(String(25),nullable=None) ipadd = Column(String(32),unique=True) type_id = Column(Integer,ForeignKey('type.tid')) # 增加relationship不会增加到数据表里,只是在ORM里表示一种关系,参数backref表示反向查询 host_type = relationship('Type',backref = 'fff') __table_args__ = ( Index('Idx_hostname','hostname'), #创建普通索引,索引名称必须写在前面 ) #创建数据表 user class User(Base): __tablename__ = 'user' uid = Column(Integer,primary_key=True,autoincrement=True) uname = Column(VARCHAR(25),nullable=False) host_id = Column(Integer,ForeignKey('host.hid')) __table_args__ = ( UniqueConstraint('uname','host_id',name='uix_uname_host_id'), #创建联合唯一索引 ) Base.metadata.create_all(engine) #创建数据表 Base.metadata.drop_all(engine) #删除数据表 #创建session会话 说到数据库,就离不开Session。Session的主要目的是建立与数据库的会话,它维护你加载和关联的所有数据库对象。它是数据库查询(Query)的一个入口。 在Sqlalchemy中,数据库的查询操作是通过Query对象来实现的。而Session提供了创建Query对象的接口。 Query对象返回的结果是一组同一映射(Identity Map)对象组成的集合。事实上,集合中的一个对象,对应于数据库表中的一行(即一条记录)。所谓同一映射, 是指每个对象有一个唯一的ID。如果两个对象(的引用)ID相同,则认为它们对应的是相同的对象。 要完成数据库查询,就需要建立与数据库的连接。这就需要用到Engine对象。一个Engine可能是关联一个Session对象,也可能关联一个数据库表。 当然Session最重要的功能还是实现原子操作。 DBsession = sessionmaker(bind=engine) session = DBsession() #插入数据 type1 = Type(tname='HP') type2 = Type(tname='IBM') type3 = Type(tname='Dell') type4 = Type(tname='联想') type_lst = [type1,type2,type3,type4] for i in type_lst: session.add(i) session.commit() host1 = Host(hostname='linux1',ipadd='10.127.55.1',type_id=1) host2 = Host(hostname='linux2',ipadd='10.127.55.2',type_id=2) host3 = Host(hostname='webserver',ipadd='10.127.55.3',type_id=3) host4 = Host(hostname='mysqlserver',ipadd='10.127.55.4',type_id=2) host5 = Host(hostname='windows server 2008',ipadd='10.127.55.5',type_id=4) host_lst = [host1,host2,host3,host4,host5] ret = session.add_all(host_lst) session.commit() User1 = User(uname='felix',host_id=1) User2 = User(uname='allan',host_id=2) User3 = User(uname='skye',host_id=3) User4 = User(uname='luke',host_id=4) User5 = User(uname='afred',host_id=5) user_lst = [User1,User2,User3,User4,User5] for i in user_lst: session.add(i) session.commit()
#导入相关模块 from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index,CHAR ,VARCHAR from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:@127.0.0.1:3306/test?charset=utf8", max_overflow=5) Base = declarative_base() #创建数据表 type class Type(Base): __tablename__ = 'type' tid = Column(Integer,primary_key=True,autoincrement=True) tname = Column(VARCHAR(25),nullable=False,unique=True) #创建数据表 host class Host(Base): __tablename__ = 'host' hid = Column(Integer,primary_key=True) hostname = Column(String(25),nullable=None) ipadd = Column(String(32),unique=True) type_id = Column(Integer,ForeignKey('type.tid')) # 增加relationship不会增加到数据表里,只是在ORM里表示一种关系,参数backref表示反向查询 host_type = relationship('Type',backref = 'fff') __table_args__ = ( Index('Idx_hostname','hostname'), #创建普通索引,索引名称必须写在前面 ) #创建数据表 user class User(Base): __tablename__ = 'user' uid = Column(Integer,primary_key=True,autoincrement=True) uname = Column(VARCHAR(25),nullable=False) host_id = Column(Integer,ForeignKey('host.hid')) __table_args__ = ( UniqueConstraint('uname','host_id',name='uix_uname_host_id'), #创建联合唯一索引 ) Base.metadata.create_all(engine) #创建数据表 Base.metadata.drop_all(engine) #删除数据表 #创建session会话 说到数据库,就离不开Session。Session的主要目的是建立与数据库的会话,它维护你加载和关联的所有数据库对象。它是数据库查询(Query)的一个入口。 在Sqlalchemy中,数据库的查询操作是通过Query对象来实现的。而Session提供了创建Query对象的接口。 Query对象返回的结果是一组同一映射(Identity Map)对象组成的集合。事实上,集合中的一个对象,对应于数据库表中的一行(即一条记录)。所谓同一映射, 是指每个对象有一个唯一的ID。如果两个对象(的引用)ID相同,则认为它们对应的是相同的对象。 要完成数据库查询,就需要建立与数据库的连接。这就需要用到Engine对象。一个Engine可能是关联一个Session对象,也可能关联一个数据库表。 当然Session最重要的功能还是实现原子操作。 DBsession = sessionmaker(bind=engine) session = DBsession()
(1)增
session.add() 增加单条记录
session.add_all() 增加多个记录
type1 = Type(tname='HP') type2 = Type(tname='IBM') type3 = Type(tname='Dell') type4 = Type(tname='联想') type_lst = [type1,type2,type3,type4] for i in type_lst: session.add(i) session.commit() host1 = Host(hostname='linux1',ipadd='10.127.55.1',type_id=1) host2 = Host(hostname='linux2',ipadd='10.127.55.2',type_id=2) host3 = Host(hostname='webserver',ipadd='10.127.55.3',type_id=3) host4 = Host(hostname='mysqlserver',ipadd='10.127.55.4',type_id=2) host5 = Host(hostname='windows server 2008',ipadd='10.127.55.5',type_id=4) host_lst = [host1,host2,host3,host4,host5] ret = session.add_all(host_lst) session.commit() User1 = User(uname='felix',host_id=1) User2 = User(uname='allan',host_id=2) User3 = User(uname='skye',host_id=3) User4 = User(uname='luke',host_id=4) User5 = User(uname='afred',host_id=5) user_lst = [User1,User2,User3,User4,User5] for i in user_lst: session.add(i) session.commit()
(2)删
ret = session.query(Host).filter(Host.hid == 2 ).delete()
print(ret)
session.commit()
执行结果
1
(3)改
session.query(Host).filter(Host.hid > 4 ).update({'hostname':'TestServer'})
session.commit()
session.query(Host).filter(Host.hid > 4).update({Host.hostname:Host.hostname + '001'}, synchronize_session=False)
session.commit()
session.query(Host).filter(Host.hid == 4).update( {'hostname': Host.hostname + '002'}, synchronize_session="fetch")
# #指定synchronize_session=False也可以
session.commit()
ret = session.query(Host).filter(Host.hid > 4).all()
print(ret[0].hid,ret[0].hostname,ret[0].type_id)
ret[0].hostname = 'TestServer'
session.commit()
(4)查
- one() 返回且仅返回一个查询结果。当结果的数量不足一个或者多于一个时会报错。
- first() 返回至多一个结果,而且以单项形式,而不是只有一个元素的tuple形式返回这个结果.
- all() 返回多个结果,组成一个列表
a.查询表里的所有数据,不带任何条件查询
#查询所有结果
ret = session.query(Host).all()
for i in ret:
print(i.hid,i.hostname,i.type_id)
执行结果
1 linux1 1
2 linux2 2
3 webserver 3
4 mysqlserver 2
5 windows server 2008 4
注意:如果想知道SQLAlchemy生成的SQL语句则
ret = session.query(Host)
print(ret)
执行结果:
SELECT host.hid AS host_hid, host.hostname AS host_hostname, host.ipadd AS host_ipadd, host.type_id AS host_type_id FROM host
b.带条件查询
- filter() 可以像写 sql 的 where 条件那样写 > < 等条件,但引用列名时,需要通过 类名.属性名 的方式。
- filter_by() 可以使用 python 的正常参数传递方法传递条件,指定列名时,不需要额外指定类名。参数名对应名类中的属性名,但不能使用 > < 等条件。
当使用filter的时候条件之间是使用“==",fitler_by使用的是"="。
filter不支持组合查询,只能连续调用filter来变相实现。而filter_by的参数是**kwargs,直接支持组合查询。
# 带条件查询
ret = session.query(Host).filter(Host.hid > 3).all()
for i in ret:
print(i.hid,i.hostname,i.type_id)
执行结果
4 mysqlserver 2
5 windows server 2008 4
# 带条件查询某一列 filter
ret = session.query(Host.hostname).filter(Host.hid == 5).all()
for i in ret:
print(i.hostname)
执行结果
windows server 2008
#带条件查询某一列 filter_by all()查询所有满足条件的
ret = session.query(Host).filter_by(hid = 5).all()
for i in ret:
print(i.hid,i.hostname,i.type_id)
执行结果
5 windows server 2008 4
#带条件查询某一列 filter_by first()满足条件的第一个
ret = session.query(Host).filter_by(hid = 1).first()
print(ret.hid,ret.hostname,ret.type_id)
执行结果
1 linux1 1
#等于条件查询
ret = session.query(Host).filter_by(hostname='mysqlserver').all()
print(ret[0].hid,ret[0].hostname)
执行结果
4 mysqlserver
#使用原生SQL语句带条件查询
ret = session.query(Host).from_statement("SELECT * FROM host where hostname=:hostname").params(hostname='mysqlserver').all()
print(ret[0].hid,ret[0].hostname,ret[0].ipadd,ret[0].type_id)
执行结果
4 mysqlserver 10.127.55.4 2
c.and、or查询,SQLAlchemy默认使用and条件,如果需要使用or查询时,需要导入or_ ,也可以导入and_进行and查询。from sqlalchemy import and_, or_
#and查询
from sqlalchemy import and_, or_
ret = session.query(Host).filter(and_(Host.hid > 1, Host.hostname == 'webserver')).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
执行结果
[<__main__.Host object at 0x000000000AFA57B8>]
3 webserver
#or条件查询
ret = session.query(Host).filter(or_(Host.hid < 2, Host.hostname == 'webserver')).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
执行结果
[<__main__.Host object at 0x000000000AFA5128>, <__main__.Host object at 0x000000000AFA5978>]
1 linux1
3 webserver
#and or 混合查询
ret = session.query(Host).filter(
or_(
Host.hid < 2,
and_(Host.hostname == 'webserver', Host.hid > 2),
Host.hostname == "windows server 2008"
)).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
执行结果
[<__main__.Host object at 0x000000000AFA3208>, <__main__.Host object at 0x000000000AFA3A58>, <__main__.Host object at 0x000000000AFA39E8>]
1 linux1
3 webserver
5 windows server 2008
d.between...and...查询
#between...and...
ret = session.query(Host).filter(Host.hid.between(1, 3)).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
# 执行结果
1 linux1
2 linux2
3 webserver
e.in和not in 查询,not in方法为 在 类名.字段.in_ 前加 ~ 取反(波浪线)
#in
ret = session.query(Host).filter(Host.hid.in_([1,3,4])).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
执行结果
[<__main__.Host object at 0x000000000AFA9748>, <__main__.Host object at 0x000000000AFA96D8>, <__main__.Host object at 0x000000000AFA97B8>]
1 linux1
3 webserver
4 mysqlserver
#not in
ret = session.query(Host).filter(~Host.hid.in_([1,3,4])).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
[<__main__.Host object at 0x000000000AFB77B8>, <__main__.Host object at 0x000000000AFB7748>]
2 linux2
5 windows server 2008
#带子查询
ret = session.query(Host).filter(Host.hid.in_(session.query(Host.hid).filter(Host.hid > 2))).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
执行结果
[<__main__.Host object at 0x000000000B05A6D8>, <__main__.Host object at 0x000000000B05A2B0>, <__main__.Host object at 0x000000000B05A780>]
3 webserver
4 mysqlserver
5 windows server 2008
f.通配符 like
# 通配符 like
ret = session.query(Host).filter(Host.hostname.like('w%')).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
ret = session.query(Host).filter(~Host.hostname.like('%server')).all()
print(ret)
for i in ret:
print(i.hid,i.hostname)
执行结果
[<__main__.Host object at 0x000000000AFA3128>, <__main__.Host object at 0x000000000AFA3588>]
3 webserver
5 windows server 2008
[<__main__.Host object at 0x000000000AFA37F0>, <__main__.Host object at 0x000000000AFA3860>, <__main__.Host object at 0x000000000AFA3588>]
1 linux1
2 linux2
5 windows server 2008
g.限制查询的结果数目 limit
# 限制 类似limit
ret = session.query(Host)[0:3] #左闭右开
print(ret)
for i in ret:
print(i.hid,i.hostname)
执行结果
[<__main__.Host object at 0x000000000AFA56A0>, <__main__.Host object at 0x000000000AFA5630>, <__main__.Host object at 0x000000000AFA5710>]
1 linux1
2 linux2
3 webserver
h.排序
# 排序
#单字段排序
ret = session.query(Host).order_by(Host.hostname.desc()).all()
for i in ret:
print(i.hid,i.hostname)
执行结果
5 windows server 2008
3 webserver
4 mysqlserver
2 linux2
1 linux1
#多字段排序
ret = session.query(Host).order_by(Host.hostname.desc(), Host.hid.asc()).all()
for i in ret:
print(i.hid,i.hostname)
执行结果
5 windows server 2008
3 webserver
4 mysqlserver
2 linux2
1 linux1
i.统计 count
#统计count
ret = session.query(Host).filter(Host.type_id == 2).count()
print(ret)
执行结果
2
j.分组加聚合函数,分组后having。使用聚合需要导入func模块
from sqlalchemy.sql import func
# 分组后count
from sqlalchemy.sql import func
ret = session.query(Host.type_id,func.count(Host.hid)).group_by(Host.type_id).all()
print(ret)
for i in ret:
print(i)
执行结果:
[(1, 1), (2, 2), (3, 1), (4, 1)]
(1, 1)
(2, 2)
(3, 1)
(4, 1)
# 分组-sum\max\min
ret = session.query(Host.type_id,
func.max(Host.hid),
func.sum(Host.hid),
func.min(Host.hid)).group_by(Host.type_id).all()
print(ret)
for i in ret:
print(i)
执行结果
[(1, 1, Decimal('1'), 1), (2, 4, Decimal('6'), 2), (3, 5, Decimal('5'), 5), (4, 3, Decimal('3'), 3)]
(1, 1, Decimal('1'), 1)
(2, 4, Decimal('6'), 2)
(3, 5, Decimal('5'), 5)
(4, 3, Decimal('3'), 3)
#分组后 having
ret = session.query(
Host.type_id,
func.max(Host.hid),
func.sum(Host.hid),
func.min(Host.hid)).group_by(Host.type_id).having(Host.type_id > 3).all()
print(ret)
for i in ret:
print(i)
执行结果
[(4, 3, Decimal('3'), 3)]
(4, 3, Decimal('3'), 3)
k.连表查询
不使用relationship进行连表查询
# 连表 默认使用inner join
#不使用join
ret = session.query(Host, Type).filter(Host.type_id == Type.tid).all()
for i in ret:
print(i[0].hostname,i[0].ipadd,i[1].tid,i[1].tname)
执行结果
linux1 10.127.55.1 1 HP
linux2 10.127.55.2 2 IBM
webserver 10.127.55.3 4 联想
mysqlserver 10.127.55.4 2 IBM
windows server 2008 10.127.55.5 3 Dell
#使用join,默认方法为inner join,在join里增加isouter=True参数,则使用left join
ret = session.query(Host,Type).join(Type,isouter=True).all()
ret = session.query(Host,Type).join(Type).all()
print(ret)
for i in ret:
print(i[0].hostname,i[0].ipadd,i[0].type_id,i[1].tname)
执行结果
linux1 10.127.55.1 1 HP
linux2 10.127.55.2 2 IBM
webserver 10.127.55.3 4 联想
mysqlserver 10.127.55.4 2 IBM
windows server 2008 10.127.55.5 2 IBM
ret = session.query(Host.hostname,Type.tname).join(Type).all()
print(ret)
for i in ret:
print(i[0],i[1])
print(i.hostname,i.tname)
执行结果
[('linux1', 'HP'), ('linux2', 'IBM'), ('webserver', '联想'), ('mysqlserver', 'IBM'), ('windows server 2008', 'IBM')]
linux1 HP
linux1 HP
linux2 IBM
linux2 IBM
webserver 联想
webserver 联想
mysqlserver IBM
mysqlserver IBM
windows server 2008 IBM
windows server 2008 IBM
使用relationship参数进行连表查询,在创建表(类)且与在增加外键的下面增加
字段名 = relationship('类名称',backref='关系名称') #增加backref参数可进行反向查询。
#relationship 正向查询
class Host(Base):
__tablename__ = 'host'
hid = Column(Integer,primary_key=True)
hostname = Column(String(25),nullable=None)
ipadd = Column(String(32),unique=True)
type_id = Column(Integer,ForeignKey('type.tid'))
# 增加relationship不会增加到数据表里,只是在ORM里表示一种关系,参数backref表示反向查询
host_type = relationship('Type',backref = 'fff')
__table_args__ = (
Index('Idx_hostname','hostname'), #创建普通索引,索引名称必须写在前面
)
host_type不会增加此字段进数据表,只是在ORM里表名两个表的关系,只能加在有外键ForeignKey的地方
#查询每台服务器的名称和类型
ret = session.query(Host).all()
for i in ret:
print(i.hid,i.hostname,i.ipadd,i.host_type.tname)
执行结果
1 linux1 10.127.55.1 HP
2 linux2 10.127.55.2 IBM
3 webserver 10.127.55.3 Dell
4 mysqlserver 10.127.55.4 IBM
5 windows server 2008 10.127.55.5 联想
#relationship 反向查询,需要加backref='名称'参数
#查询每一种类型所有的host
#不加relationship且不加backref='fff'参数
type_lst = session.query(Type)
for i in type_lst:
print(i.tid,i.tname,session.query(Host).filter(Host.type_id == i.tid).all())
执行结果
3 Dell [<__main__.Host object at 0x000000000AFD19B0>]
1 HP [<__main__.Host object at 0x000000000AFD1B38>]
2 IBM [<__main__.Host object at 0x000000000AFD1C50>, <__main__.Host object at 0x000000000AFD1CC0>]
4 联想 [<__main__.Host object at 0x000000000AFD1D30>]
#加relationship参数且加入 backref='fff'参数,fff为名称,即反向查询
type_lst = session.query(Type).all()
for i in type_lst:
print(i.tid,i.tname,i.fff)
执行结果
3 Dell [<__main__.Host object at 0x000000000AFE6160>]
1 HP [<__main__.Host object at 0x000000000AFE6208>]
2 IBM [<__main__.Host object at 0x000000000AFE62B0>, <__main__.Host object at 0x000000000AFE6320>]
4 联想 [<__main__.Host object at 0x000000000AFE6390>]
#说明 每一种类型可能有一个或多个主机,因此print(i.fff)就表示主机的对象,因此可以使用两层for循环取到主机信息
type_lst = session.query(Type).all()
for i in type_lst:
for j in i.fff:
print(i.tid, i.tname, j.hostname)
执行结果:
3 Dell webserver
1 HP linux1
2 IBM linux2
2 IBM mysqlserver
4 联想 windows server 2008
l.组合 union
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()