zoukankan      html  css  js  c++  java
  • SQLAlchemy

    一、CRM介绍

      数据库表是一个二维表,包含多行多列。把一个表的内容用Python的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是tuple,表示一行记录,比如,包含idnameuser表:

    [
        ('1', 'Michael'),
        ('2', 'Bob'),
        ('3', 'Adam')
    ]
    

      Python的DB-API返回的数据结构就是像上面这样表示的。

      但是用tuple表示一行很难看出表的结构。如果把一个tuple用class实例来表示,就可以更容易地看出表的结构来:

    class User(object):
        def __init__(self, id, name):
            self.id = id
            self.name = name
    
    [
        User('1', 'Michael'),
        User('2', 'Bob'),
        User('3', 'Adam')
    ]
    

      这就是传说中的ORM技术:Object-Relational Mapping,把关系数据库的表结构映射到对象上。 

      在Python中,最有名的ORM框架是SQLAlchemy。

    二、SqlAlchemy基本操作

      SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

        

      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
    

      

      安装SQLAlchemy、mysql-connector

      pip  install SQLAlchemy

      pip  install --egg mysql-connector

      1、使用 Engine/ConnectionPooling/Dialect 进行数据库操作,Engine使用ConnectionPooling连接数据库,然后再通过Dialect执行SQL语句。    

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
      
    from sqlalchemy import create_engine
      
    # 初始化数据库连接  
    engine = create_engine("mysql+mysqlconnector://root:123,.abc@127.0.0.1:3306/s12day9", max_overflow=5)
      
    engine.execute(
        "INSERT INTO test (id, name) VALUES ('2', 'Rambo')"
    )
      
    #engine.execute(
    #     "INSERT INTO test (a, b) VALUES (%s, %s)",
    #    ((555, "v1"),(666, "v1"),)
    #)
    #engine.execute(
    #    "INSERT INTO test (a, b) VALUES (%(id)s, %(name)s)",
    #    id=999, name="v1"
    #)
      
    result = engine.execute('select * from test')
    result.fetchall()
    

      

      2、使用 Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 进行数据库操作。Engine使用Schema Type创建一个特定的结构对象,之后通过SQL Expression Language将该对象转换成SQL语句,然后通过 ConnectionPooling 连接数据库,再然后通过 Dialect 执行SQL,并获取结果。  

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey
    
    metadata = MetaData()
    
    user = Table('users', metadata,
        Column('id', Integer, primary_key=True),
        Column('name', String(20)),
    )
    
    color = Table('color', metadata,
        Column('id', Integer, primary_key=True),
        Column('name', String(20)),
    )
    engine = create_engine("mysql+mysqlconnector://root:123,.abc@localhost:3306/s12day9", max_overflow=5)
    
    metadata.create_all(engine)
    

      增删改查

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey, select
    
    metadata = MetaData()
    
    user = Table('users', metadata,
        Column('id', Integer, primary_key=True),
        Column('name', String(20)),
    )
    
    color = Table('color', metadata,
        Column('id', Integer, primary_key=True),
        Column('name', String(20)),
    )
    engine = create_engine("mysql+mysqlconnector://root:123,.abc@127.0.0.1:3306/s12day9", max_overflow=5)
    
    conn = engine.connect()
    
    # 创建SQL语句,INSERT INTO "user" (id, name) VALUES (:id, :name)
    #conn.execute(user.insert(),{'id':1,'name':'flash'})
    #conn.close()
    
    # 插入数据的另一种方法
    #sql = user.insert().values(id=2, name='Rambo')
    #conn.execute(sql)
    #conn.close()
    
    # 删除id大于1的记录 
    #sql = user.delete().where(user.c.id > 1)
    #conn.execute(sql)
    #conn.close()
    
    sql = user.update().values(fullname=user.c.name)
    sql = user.update().where(user.c.name == 'jack').values(name='ed')
    
    sql = select([user, ])
    sql = select([user.c.id, ])
    sql = select([user.c.name, color.c.name]).where(user.c.id==color.c.id)
    sql = select([user.c.name]).order_by(user.c.name)
    sql = select([user]).group_by(user.c.name)
    
    result = conn.execute(sql)
    print(result.fetchall())
    conn.close()
    

     

       完整的例子:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    # 导入 from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String from sqlalchemy.orm import sessionmaker
    # 创建对象的基类 Base = declarative_base() # 初始化数据库连接, echo为False表示不显示消息,为True则显示。 engine = create_engine("mysql+mysqlconnector://root:123,.abc@localhost:3306/s12day9",ec ho=False) class Host(Base):
      # 表的名字 __tablename__ = 'hosts'
      # 表的结构 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)
    # 生成一个SqlORM 基类

    Base.metadata.create_all(engine)

      以上代码完成SQLAlchemy的初始化和具体每个表的class定义。如果有多个表,就继续定义其他class,例如app:

    class app(Base):
        __tablename__ = 'school'
        id = ...
        name = ...
    

      创建数据库会话,往数据库添加记录: 

    if __name__ == '__main__':
        # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
        SessionCls = sessionmaker(bind=engine) 
        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(h3)             #将h3添加到session
        #session.add_all( [h1,h2])  #批量添加 
        h2.hostname = 'ubuntu_test' #只要没提交,此时修改也没问题
    #session.rollback()
      # 创建Query查询,filter是where条件,最后调用all()返回所有行,调用one()则返回唯一行
    # res=session.query(Host).filter(Host.hostname.in_(['ubuntu2','localhost'])).all()
    # print(res)

    ### 先查询后修改
       #res = session.query(Host).filter(Host.hostname=="localhost").first()
    #res.hostname = "test server"

    ### 先查询后删除

             #res = session.query(Host).filter(Host.hostname=="test server").first()
             #session.delete(res)

        session.commit() #提交  

    更多内容详见:

        http://www.jianshu.com/p/e6bba189fcbd

        http://docs.sqlalchemy.org/en/latest/core/expression_api.html  

      3、使用 ORM/Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 所有组件对数据进行操作。根据类创建对象,对象转换成SQL,执行SQL。 

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String
    from sqlalchemy.orm import sessionmaker
    from sqlalchemy import create_engine
     
    engine = create_engine("mysql+mysqlconnector://root:123,.abc@127.0.0.1:3306/s12day9", max_overflow=5)
     
    Base = declarative_base()
     
     
    class User(Base):
        __tablename__ = 'users'
        id = Column(Integer, primary_key=True)
        name = Column(String(50))
     
    # 寻找Base的所有子类,按照子类的结构在数据库中生成对应的数据表信息
    # Base.metadata.create_all(engine)
     
    Session = sessionmaker(bind=engine)
    session = Session()
     
     
    # ########## 增 ##########
    # u = User(id=2, name='sb')
    # session.add(u)
    # session.add_all([
    #     User(id=3, name='sb'),
    #     User(id=4, name='sb')
    # ])
    # session.commit()
     
    # ########## 删除 ##########
    # session.query(User).filter(User.id > 2).delete()
    # session.commit()
     
    # ########## 修改 ##########
    # session.query(User).filter(User.id > 2).update({'cluster_id' : 0})
    # session.commit()
    # ########## 查 ##########
    # ret = session.query(User).filter_by(name='sb').first()
     
    # ret = session.query(User).filter_by(name='sb').all()
    # print ret
     
    # ret = session.query(User).filter(User.name.in_(['sb','bb'])).all()
    # print ret
     
    # ret = session.query(User.name.label('name_label')).all()
    # print ret,type(ret)
     
    # ret = session.query(User).order_by(User.id).all()
    # print ret
     
    # ret = session.query(User).order_by(User.id)[1:3]
    # print ret
    # session.commit()
    

      

    三、外键关联

      由上面的例子可以看出,ORM就是把数据库表的行与相应的对象建立关联,互相转换。

      由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应地,ORM框架也可以提供两个对象之间的一对多、多对多等功能。

      

      例如,如果一个Group拥有多个Host,就可以定义一对多(一个组可以对应多个主机,但一个主机只能对应一个组)关系如下:

    class Host(Base):
        __tablename__ = 'hosts'
        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'))    
    class Group(Base): __tablename__ = 'group' id = Column(Integer,primary_key=True) name = Column(String(64),unique=True,nullable=False) # host_id = Column(Integer,ForeignKey('host.id')) # 如果host_id写在Group里,就相当于一对一了,一个组对应一台主机,所以一定要写在host里面

      

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 
     4 from sqlalchemy import create_engine
     5 from sqlalchemy import Table, Column, Integer, String, ForeignKey
     6 from sqlalchemy.orm import relationship
     7 from sqlalchemy.ext.declarative import declarative_base
     8 from  sqlalchemy.orm import sessionmaker
     9 
    10 Base = declarative_base()
    11 
    12 engine = create_engine("mysql+mysqlconnector://root:123,.abc@localhost:3306/s12day9",echo=True)
    13 
    14 
    15 class Host(Base):
    16     __tablename__ = 'hosts'
    17     id = Column(Integer,primary_key=True,autoincrement=True)
    18     hostname = Column(String(64),unique=True,nullable=False)
    19     ip_addr = Column(String(128),unique=True,nullable=False)
    20     port = Column(Integer,default=22)
    21     group_id = Column(Integer,ForeignKey('group.id'))
    22 
    23 class Group(Base):
    24     __tablename__ = 'group'
    25     id = Column(Integer,primary_key=True)
    26     name = Column(String(64),unique=True,nullable=False)
    27     # host_id = Column(Integer,ForeignKey('host.id'))
    28 
    29 Base.metadata.create_all(engine) #创建所有表结构
    30 
    31 if __name__ ==  '__main__':
    32     SessionCls = sessionmaker(bind=engine)
    33     session = SessionCls()
    34     session.commit()
    一对多
    2016-06-28 23:27:58,944 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode'
    2016-06-28 23:27:58,944 INFO sqlalchemy.engine.base.Engine {}
    2016-06-28 23:27:58,951 INFO sqlalchemy.engine.base.Engine SELECT DATABASE()
    2016-06-28 23:27:58,951 INFO sqlalchemy.engine.base.Engine {}
    2016-06-28 23:27:58,957 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAR(60)) AS anon_1
    2016-06-28 23:27:58,957 INFO sqlalchemy.engine.base.Engine {}
    2016-06-28 23:27:58,961 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_1
    2016-06-28 23:27:58,962 INFO sqlalchemy.engine.base.Engine {}
    2016-06-28 23:27:58,964 INFO sqlalchemy.engine.base.Engine DESCRIBE `hosts`
    2016-06-28 23:27:58,964 INFO sqlalchemy.engine.base.Engine {}
    2016-06-28 23:27:58,965 INFO sqlalchemy.engine.base.Engine ROLLBACK
    2016-06-28 23:27:58,967 INFO sqlalchemy.engine.base.Engine DESCRIBE `group`
    2016-06-28 23:27:58,967 INFO sqlalchemy.engine.base.Engine {}
    2016-06-28 23:27:58,969 INFO sqlalchemy.engine.base.Engine ROLLBACK
    2016-06-28 23:27:58,972 INFO sqlalchemy.engine.base.Engine 
    CREATE TABLE `group` (
    	id INTEGER NOT NULL AUTO_INCREMENT, 
    	name VARCHAR(64) NOT NULL, 
    	PRIMARY KEY (id), 
    	UNIQUE (name)
    )
    
    
    2016-06-28 23:27:58,972 INFO sqlalchemy.engine.base.Engine {}
    2016-06-28 23:27:59,018 INFO sqlalchemy.engine.base.Engine COMMIT
    2016-06-28 23:27:59,019 INFO sqlalchemy.engine.base.Engine 
    CREATE TABLE hosts (
    	id INTEGER NOT NULL AUTO_INCREMENT, 
    	hostname VARCHAR(64) NOT NULL, 
    	ip_addr VARCHAR(128) NOT NULL, 
    	port INTEGER, 
    	group_id INTEGER, 
    	PRIMARY KEY (id), 
    	UNIQUE (hostname), 
    	UNIQUE (ip_addr), 
    	FOREIGN KEY(group_id) REFERENCES `group` (id)
    )
    
    
    2016-06-28 23:27:59,019 INFO sqlalchemy.engine.base.Engine {}
    2016-06-28 23:27:59,064 INFO sqlalchemy.engine.base.Engine COMMIT
    

      注:SQLAlchemy无法修改表结构(如果需要可以使用SQLAlchemy开发者开源的另外一个软件Alembic来完成),所以这里先删除hosts表(测试环境)再重新创建。

    更多功能参见文档,猛击这里下载PDF

    总结: 

      ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。

      正确使用ORM的前提是了解关系数据库的原理。

    运维因自动化而有趣!
  • 相关阅读:
    在ThinkPHP中生成中文验证码
    Touch event in certain color rect
    安装GD后不支持PNG或JPG的修复办法
    iPhone开发:proximityMonitoring邻近检测
    开放CSDN博客-欢迎到访-另附声明
    (实例篇)LNMP 1.4一键安装包,安装教程
    流量相关说明
    一个空间主机安装多个网站的方法
    怎么使用linux命令重启服务器
    CentOS、Ubuntu、Debian三个linux比较异同
  • 原文地址:https://www.cnblogs.com/Rambotien/p/5624805.html
Copyright © 2011-2022 走看看