ORM解决的问题
当你的应用程序需要跟数据库大量交互时,如果你直接把sql语句写到代码中,
1.会出现大量的重复代码。(可以把重复的sql语句写成一个函数)
2.当你的后端数据库改变后,你的代码需要重写。
测试:
MySQL数据库
pymysql模块
创建一个test库
一、单表操作
1.创建表
#!/usr/bin/env python #-*- coding:utf-8 -*- from sqlalchemy import create_engine,func from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String,ForeignKey from sqlalchemy.orm import sessionmaker,relationship Base = declarative_base() #生成一个SqlORM 基类 engine = create_engine("mysql+pymysql://root:123.com@localhost:3306/test",echo=True) #echo = True 会打印执行过程 class Host(Base): #创建一个类,继承base __tablename__ = 'hosts' id = Column(Integer,primary_key=True,autoincrement=True) #主键primary_key默认就是True,自增id hostname = Column(String(64),unique=True,nullable=False) ip_addr = Column(String(128),unique=True,nullable=False) port = Column(Integer,default=22) #默认是22 Base.metadata.create_all(engine) 打印出的sql语句 CREATE TABLE hosts ( id INTEGER NOT NULL AUTO_INCREMENT, hostname VARCHAR(64) NOT NULL, ip_addr VARCHAR(128) NOT NULL, port INTEGER, PRIMARY KEY (id), UNIQUE (hostname), UNIQUE (ip_addr) )
2.增加数据
#!/usr/bin/env python #-*- coding:utf-8 -*- from sqlalchemy import create_engine,func from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String,ForeignKey from sqlalchemy.orm import sessionmaker,relationship Base = declarative_base() #生成一个SqlORM 基类 engine = create_engine("mysql+pymysql://root:123.com@localhost:3306/test",echo=True) #echo = True 会打印执行过程 class Host(Base): #创建一个类,继承base __tablename__ = 'hosts' id = Column(Integer,primary_key=True,autoincrement=True) #主键primary_key默认就是True,自增id hostname = Column(String(64),unique=True,nullable=False) ip_addr = Column(String(128),unique=True,nullable=False) port = Column(Integer,default=22) #默认是22 # Base.metadata.create_all(engine) if __name__ == '__main__': #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例 #sessionmaker自己是一个类,返回的是一个类.(__call__方法返回) SessionCls = sessionmaker(bind=engine) #所以你想生成你的session还需要session = SessionCls() session = SessionCls() #写数据信息 h1 = Host(hostname='localhost',ip_addr='127.0.0.1') h2 = Host(hostname='ubuntu',ip_addr='192.168.2.243',port=20000) h3 = Host(hostname='ubuntu2',ip_addr='192.168.2.244',port=20000) #添加数据 #第一种方法 # session.add(h1) # session.add(h2) # session.add(h3) #第二种方法 session.add_all([h1,h2,h3]) #只要没提交,此时修改也没问题 # h2.hostname = 'ubuntu_test' # session.rollback() session.commit() #提交
INSERT INTO hosts (hostname, ip_addr, port) VALUES (%(hostname)s, %(ip_addr)s, %(port)s)
{'ip_addr': '127.0.0.1', 'hostname': 'localhost', 'port': 22}
3.查询数据
res = session.query(Host).filter(Host.hostname.in_(['ubuntu2','localhost'])).all() for i in res: print(i.hostname,i.ip_addr)
二、一对多
****** 一对多 ****** 一个组可以包含多个主机,一个主机只能属于一个组 A ------ G1,admin,permission B ------ G1,admin,permission C ------ G2,admin,permission C ------ G1,admin,permission 缺点: 有大部分重复字段,浪费空间 在修改时,可能会出现错误 主机表一个字段连接组表的一个字段 主机表 组表 A 1 ----- 1 G1 admin permssion B 1 ----- 2 G1 admin permssion C 2 ----- 3 G2 admin permssion C 1 ----- 4 G1 admin permssion 查询 通过表一可以查询表二,通过表二可以查询表一 当数据库表中添加新的字段,sqlalchemy无法操作。所以当你添加字段有两个方法. 1.把表删了,重新创建 2.原生语句添加 3.sqlalchemy有个开源工具可以实现 这么添加host表中的group_id是空值,没有关联上 g1 = Group(name='g1') g2 = Group(name='g2') g3 = Group(name='g3') session.add_all([g1,g2,g3]) h1 = Host(hostname='localhost',ip_addr='127.0.0.1',group_id = g3.id) session.add(h1) session.commit() #update 参数是一个字典 h1 = session.query(Host).filter(Host.hostname == 'localhost').update({'group_id':g4.id}) 查询: 通过host表获取组的名字,或者通过group表获取host主机.都需要用到 relationship group = relationship("Group") #相当于反射,把Group类反射到Host.group字段 2.查看组里多少台主机 g3 = session.query(Group).filter(Group.name=='g3').first() obj = g3.host_list #1 print(obj[0].hostname) #2 for i in obj: print(i.hostname) join 查询 1.查询两个表的交集 select * from hosts join test.group on hosts.group_id = test.group.id; 2.right outer join 右边全列出来,左边如果没有就是null 3.left join 左边全列出来,右边没有就是null 4.full outer join 全显示出来 分组聚合:查看每个组里有几台机器 原生sql版本 select Count(*),test.group.name from hosts inner join test.group on hosts.group_id = test.group.id group by test.group.name; orm版本 需要func模块,包含count方法 #查询host组,以组名为条件,查询每个组名下的主机个数 obj = session.query(Host,func.count(Group.name)).join(Host.group).group_by(Group.name).all() 一、创建组表 二、创建主机表 三、创建关联
#!/usr/bin/env python #-*- coding:utf-8 -*- from sqlalchemy import create_engine,func from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String,ForeignKey from sqlalchemy.orm import sessionmaker,relationship Base = declarative_base() #生成一个SqlORM 基类 engine = create_engine("mysql+pymysql://root:123.com@localhost:3306/test",echo=True) #echo = True 会打印执行过程 class Host(Base): #创建一个类,继承base __tablename__ = 'hosts' id = Column(Integer,primary_key=True,autoincrement=True) #主键primary_key默认就是True,自增id hostname = Column(String(64),unique=True,nullable=False) ip_addr = Column(String(128),unique=True,nullable=False) port = Column(Integer,default=22) #默认是22 group_id = Column(Integer,ForeignKey('group.id')) # 第一种 group = relationship("Group",backref='host_list') #backref是group查询host的字段 class Group(Base): __tablename__ = 'group' id = Column(Integer,primary_key=True,autoincrement=True) name = Column(String(64),unique=True,nullable=False) # Base.metadata.create_all(engine) if __name__ == '__main__': SessionCls = sessionmaker(bind=engine) session = SessionCls() #添加组信息 # g1 = Group(name='g1') # g2 = Group(name='g2') # g3 = Group(name='g3') # session.add_all([g1,g2,g3]) #查询组名 # g2 = session.query(Group).filter(Group.name == 'g2').first() # g3 = session.query(Group).filter(Group.name == 'g3').first() # print(g2.id) #添加主机信息 # h1 = Host(hostname='localhost',ip_addr='127.0.0.1',group_id = g3.id) # h2 = Host(hostname='ubuntu',ip_addr='192.168.2.243',port=20000,group_id = g3.id) # h3 = Host(hostname='ubuntu2',ip_addr='192.168.2.244',port=20000,group_id = g2.id) #查询主机信息 # h1 = session.query(Host).filter(Host.hostname == 'localhost').update({'group_id':g2.id}) # session.add_all([h1,h2,h3]) # ret = session.query(Host).filter(Host.hostname == 'ubuntu2').delete() # session.commit() #查询一个组里面有多少个主机 # g3 = session.query(Group).filter(Group.name == 'g2').first() # obj = g3.host_list # for i in obj: # print(i.hostname +'-----' + i.ip_addr) obj = session.query(Host,func.count(Group.name)).join(Host.group).group_by(Group.name).all() print(obj) #删除一条数据 # ret = session.query(Host).filter(Host.hostname == 'ubuntu2').delete() #更新一个字段 #h1 = session.query(Host).filter(Host.hostname == 'localhost').update({'group_id':g2.id})
三、多对多
多对多 一个主机可以属于多个组,一个组里可以包含多个主机 ------------ h1 g1 ip port #当我改这条数据组的信息时,如果不改第二条,那么h1的数据就是有问题的,这样不能做到多对多。 h1 g2 ip port h2 g1 ip port 建一个第三张表 host hosttogroup group ===================================================== id 主机 id host_id group_id id 组名 ===================================================== 1 h1 1 1 1 1 g1 2 h2 2 1 2 2 g2 3 2 1 两种方式创建表 1.通过类创建,需要实例化 Host2Group = Table('host_2_group',Base.metadata, Column('host_id',ForeignKey('host.id'),primary_key=True), Column('group_id',ForeignKey('group.id'),primary_key=True), ) 2.table方式(中间状态),返回的是一个对象,不需要实例化 class Group(Base): __tablename__ = 'group' id = Column(Integer,primary_key=True,autoincrement=True) name = Column(String(64),unique=True,nullable=False) 关联参数 class Host(Base): __tablename__ = 'host' id = Column(Integer,primary_key=True,autoincrement=True) hostname = Column(String(64),unique=True,nullable=False) ip_addr = Column(String(128),unique=True,nullable=False) port = Column(Integer,default=22) # group_id = Column(Integer,ForeignKey('group.id')) group = relationship("Group", secondary=Host2Group, #secondary=第三章表名 backref='host_list') #反向关联,实现相互查询 table表要设置两个主键,因为两个列成为一个主键,非空且唯一。 id host_id group_id 1 null 1 2 1 1 3 1 1 关联: groups = session.query(Group).all() h1 = session.query(Host).filter(Host.hostname == 'h1').first() h1.groups = groups 一、建一个中间表,关联其它两张表 二、指定中间表的实例 #secondary=Host2Group 三、先创建三张表 四、创建组数据 五、创建主机数据
#!/usr/bin/env python #-*- coding:utf-8 -*- from sqlalchemy import create_engine,func,Table from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String,ForeignKey from sqlalchemy.orm import sessionmaker,relationship Base = declarative_base() #返回的直接是表的对象 #中间表,关联其它两个表id,并设置为主键. Host2Group = Table('host_2_group',Base.metadata, Column('host_id',ForeignKey('host.id'),primary_key=True), Column('group_id',ForeignKey('group.id'),primary_key=True), ) engine = create_engine("mysql+pymysql://root:123.com@localhost:3306/tests",echo=True) class Host(Base): __tablename__ = 'host' id = Column(Integer,primary_key=True,autoincrement=True) hostname = Column(String(64),unique=True,nullable=False) ip_addr = Column(String(128),unique=True,nullable=False) port = Column(Integer,default=22) # group_id = Column(Integer,ForeignKey('group.id')) group = relationship("Group", secondary=Host2Group, backref='host_list') #反向关联,实现相互查询 #返回字符串 def __repr__(self): return "<id=%s,hostname=%s,ip_addr=%s>" % (self.id, self.hostname, self.ip_addr,) class Group(Base): __tablename__ = 'group' id = Column(Integer,primary_key=True,autoincrement=True) name = Column(String(64),unique=True,nullable=False) def __repr__(self): return "<id=%s,name=%s>" % (self.id, self.name,) # Base.metadata.create_all(engine) #创建所有表结构 if __name__ == '__main__': SessionCls = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例 session = SessionCls() #创建组数据 # g1 = Group(name='g1') # g2 = Group(name = 'g2') # g3 = Group(name = 'g3') # session.add_all([g1,g2,g3]) #创建主机数据 groups = session.query(Group).all() # h1 = Host(hostname='h1',ip_addr='192.168.0.1') # h1.group = groups h3 = Host(hostname='ubuntu3',ip_addr='192.168.2.222',port=20000) # h2 = session.query(Host).filter(Host.hostname == 'h2').first() h3.group = groups[0:2] # h3 = Host(hostname='ubuntu2',ip_addr='192.168.2.244',port=20000) # session.add_all([h1,h2]) session.commit()