1、CRM介紹php
數據庫表是一個二維表,包含多行多列。把一個表的內容用Python的數據結構表示出來的話,能夠用一個list表示多行,list的每個元素是tuple,表示一行記錄,好比,包含id
和name
的user
表: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的前提是瞭解關係數據庫的原理。