sqlalchemy

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()

  

原文地址:https://www.cnblogs.com/Z-style/p/6011031.html