SQLAlchemy

1、CRM介紹php

  數據庫表是一個二維表,包含多行多列。把一個表的內容用Python的數據結構表示出來的話,能夠用一個list表示多行,list的每個元素是tuple,表示一行記錄,好比,包含idnameuser表:html

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

  Python的DB-API返回的數據結構就是像上面這樣表示的。python

  可是用tuple表示一行很難看出表的結構。若是把一個tuple用class實例來表示,就能夠更容易地看出表的結構來:mysql

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,把關係數據庫的表結構映射到對象上。 sql

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

 

2、SqlAlchemy基本操做express

  SQLAlchemy是Python編程語言下的一款ORM框架,該框架創建在數據庫API之上,使用關係對象映射進行數據庫操做,簡言之即是:將對象轉換成SQL,而後使用數據API執行SQL並獲取執行結果。編程

 

    

  Dialect用於和數據API進行交流,根據配置文件的不一樣調用不一樣的數據庫API,從而實現對數據庫的操做,如:  ubuntu

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-connectorapi

  pip  install SQLAlchemy

  pip  install --egg mysql-connector

 

  一、使用 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()

  

  二、使用 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()
   # 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"

### 先查詢後刪除# 建立Query查詢,filter是where條件,最後調用all()返回全部行,調用one()則返回惟一行

         #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  

 

  三、使用 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()

  

3、外鍵關聯

  由上面的例子能夠看出,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的前提是瞭解關係數據庫的原理。

相關文章
相關標籤/搜索