SQLAlchemy是Python編程語言下的一款ORM框架,該框架創建在數據庫API之上,使用關係對象映射進行數據庫操做,簡言之即是:將對象轉換成SQL,而後使用數據API執行SQL並獲取執行結果。python
雖然小弟是個小菜鳥,雖然小弟對數據庫沒有見多識廣,但說內心話當我看到SQLAlchemy這個架構設計時,真的有一種神奇的感受。簡潔明瞭,邏輯清晰。原諒小弟lowB的心態。最關鍵的是不須要再研究那些複雜繁瑣的數據庫操做細節了。mysql
使用SQLAlchemy操做數據庫的方式方法有不少種,如經過執行原生SQL語句操做,經過對象操做等。可是在這裏只介紹一種最終執行結果的操做,而不是相似中間狀態的一些操做。sql
使用 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
Base = declarative_base()
engine = create_engine("mysql+mysqldb://root:123456@192.168.1.106:3306/test1", max_overflow=5, echo=True) # echo控制是否顯示操做過程
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)
prot = Column(Integer, default=22)
# 尋找Base的全部子類,按照子類的結構在數據庫中生成對應的數據表信息
Base.metadata.create_all(engine) # 建立全部的表結構
if __name__ == '__main__':
SessionCls = sessionmaker(bind=engine) # 建立與數據庫會話的session class,返回的是一個類,而不是一個實例
session = SessionCls() # 鏈接數據庫的實例,就是用它來對數據庫作實際的操做
# ###################### 增 #############################
# 建立表中數據的實例
# h1 = Host(hostname='localhost', ip_addr='127.0.0.1')
# h2 = Host(hostname='centos', ip_addr='172.16.16.166')
# session.add(h1) # 單條建立
# session.add_all([h1, h2]) # 批量建立
# session.commit() # 真正的提交數據庫操做
# ###################### 查 ###########################
# obj = session.query(Host).filter(Host.hostname == 'centos').all()
# print obj
# ret = session.query(User).filter_by(name='sb').first()
# ret = session.query(User).filter_by(name='sb').all()
# ret = session.query(User).filter(User.name.in_(['sb','bb'])).all()
# ret = session.query(User.name.label('name_label')).all()
# print ret,type(ret)
# ret = session.query(User).order_by(User.id).all()
# ret = session.query(User).order_by(User.id)[1:3]
# session.commit()
# ###################### 刪除 ###########################
# obj = session.query(Host).filter(Host.hostname == 'centos').first()
# session.delete(obj)
#
# session.commit()
# ###################### 更新 ###########################
# obj = session.query(Host).filter_by(hostname='localhost').first()
# obj.hostname = "chenchao"
# print obj
# session.commit()
更多功能參見文檔,猛擊這裏下載PDF編程
注意:SQLAlchemy不能修改已經存在的表的表結構。若是須要可使用SQLAlchemy開發者開源的另一個軟件Alembic來完成。centos
因爲SQLAlchemy不能對已經存在的表修改表結構,處於測試的緣由,咱們能夠建立新的表。session
一、建立表架構
#!/usr/bin/env python
# _*_coding:utf-8 _*_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
Base = declarative_base()
engine = create_engine("mysql+mysqldb://root:123456@192.168.1.106:3306/test1", max_overflow=5, echo=True)
class Host1(Base): # 這個類就是一個表,這裏只是映射成功了
__tablename__ = 'hosts1'
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)
prot = Column(Integer, default=22)
group_id = Column(Integer, ForeignKey('group1.id'))
class Group1(Base):
__tablename__ = 'group1'
id = Column(Integer, primary_key=True)
groupname = Column(String(64), unique=True, nullable=False)
# 尋找Base的全部子類,按照子類的結構在數據庫中生成對應的數據表信息
Base.metadata.create_all(engine) # 建立全部的表結構
結果:框架
二、 建立數據:編程語言
if __name__ == '__main__': SessionCls = sessionmaker(bind=engine) # 建立與數據庫會話的session class,返回的是一個類,而不是一個實例
session = SessionCls() # 鏈接的實例
g1 = Group1(groupname='g1') g2 = Group1(groupname='g2') g3 = Group1(groupname='g3') session.add_all([g1, g2, g3]) # 同時爲host1建立兩條數據,但外鍵的參數不一樣。
h1 = Host1(hostname='chenchao1', ip_addr='192.168.1.1',group_id=g1.id) h2 = Host1(hostname='chenchao2', ip_addr='192.168.1.2',group_id=2) session.add_all([h1, h2]) session.commit()
用傳入對象的方法和直接傳id的方法分別建立兩條外鍵的數據。
結果:
咱們發現當在建立數據的時候,傳入對象並不能建立外鍵的值。由於當時的group表裏面尚未數據。因此在插入外鍵數據時要確保對應的數據已經存在。
SessionCls = sessionmaker(bind=engine) # 建立與數據庫會話的session class,返回的是一個類,而不是一個實例
session = SessionCls() # 鏈接的實例
g3 = session.query(Group1).filter(Group1.groupname == 'g3').first() h3 = session.query(Host1).filter(Host1.hostname == 'chenchao1').update({'group_id': g3.id}) session.commit()
三、查找外鍵數據
在host表裏經過定義某個字段就能夠調用這個字段來獲取外鍵表中的某個數據。
注意:這裏的方法是sqlalchemy來幫咱們實現的。並非要修改數據庫中的表結構。
from sqlalchemy.orm import relationship # 導入
class Host1(Base): # 這個類就是一個表,這裏只是映射成功了
__tablename__ = 'hosts1'
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)
prot = Column(Integer, default=22)
group_id = Column(Integer, ForeignKey('group1.id'))
group = relationship('Group1') #定義一個特殊的字段。括號裏寫的是一個類名,而不是表名
if __name__ == '__main__':
SessionCls = sessionmaker(bind=engine)
session = SessionCls() # 鏈接的實例
h3 = session.query(Host1).filter(Host1.hostname == 'chenchao1').first()
print h3.group.groupname # 經過調用設置的字段就能夠獲取到外鍵表中的對應數據
session.commit()
同理,若是要實現雙向查詢,那麼把relationship()也添加到Group類裏面,能夠實現雙向查詢。可是,也能夠只在Host表裏作雙向查詢。
class Host1(Base): # 這個類就是一個表,這裏只是映射成功了
__tablename__ = 'hosts1' 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) prot = Column(Integer, default=22) group_id = Column(Integer, ForeignKey('group1.id')) group = relationship('Group1', backref='host_list') #添加特殊的字段
g2 = session.query(Group1).filter(Group1.groupname == 'g2').first() # 獲取組的對象
print g2.host_list # 經過自定義的host_list來實現雙向的查詢
幾個Join的區別 http://stackoverflow.com/questions/38549/difference-between-inner-and-outer-joins
join查詢能夠根據兩張表中有關聯的數據來對錶中的數據作處理。
一、原生SQL查詢
Inner join # select * from a INNER JOIN b on a.a = b.b; # select a.*,b.* from a,b where a.a = b.b;
# 根據hosts1表中的group_id與group1表中的id來取出交集 # select * from hosts1 INNER JOIN group1 on hosts1.group_id = group1.id;
Left outer join # select * from a LEFT OUTER JOIN b on a.a = b.b; # select a.*,b.* from a,b where a.a = b.b(+);
# 根據hosts1表中的group_id與group1表中的id來取出左邊表中的數據 # select * from hosts1 LEFT OUTER JOIN group1 on hosts1.group_id = group1.id;
Right outer join # select * from a RIGHT OUTER JOIN b on a.a = b.b; # select a.*,b.* from a,b where a.a(+) = b.b;
# 根據hosts1表中的group_id與group1表中的id來取出右邊表中的數據 # select * from hosts1 RIGHT OUTER JOIN group1 on hosts1.group_id = group1.id;
二、SQLAlchemy查詢
obj = session.query(Host1).join(Host1.group).all()
三、group by 查詢 (這裏很懵逼,小弟對原生SQL也不懂)
分類聚合。
obj = session.query(Host1, func.count(Group1.groupname)).join(Host1.group).group_by(Group1.groupname).all()
上面一行代碼解釋:
一、基於相同主機組,經過join來查找兩張表中交集的數據
二、統計出交集組裏包含的主機個數
三、並按主機組名和主機個數顯示。
在SQLAlchemy裏,多對多的關聯一樣是經過創建第三張關係表來實現的。在這裏須要把建立第三張表放在開始位置,且是經過SQLAlchemy的中間狀態來實現的。
#!/usr/bin/env python
# _*_coding:utf-8 _*_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, func, Table
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine
Base = declarative_base()
engine = create_engine("mysql+mysqldb://root:123456@192.168.1.106:3306/test1", max_overflow=5, echo=False)
# 經過中間狀態的方法建立第三張關係表,關聯其餘兩張表
HostToGroup = Table('host_to_group', Base.metadata,
Column('host_id', ForeignKey('hostsmsg.id'), primary_key=True),
Column('group_id', ForeignKey('GroupMsg.id'), primary_key=True),
)
class HostMsg(Base):
__tablename__ = 'hostsmsg'
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)
prot = Column(Integer, default=22)
group = relationship('GroupMsg', backref='host_list', secondary=HostToGroup) # 添加第三張表的實例
# 設置回顯對象的詳細信息
def __repr__(self):
return "<id=%s, hostname=%s, ip_addr=%s>" % (self.id, self.hostname, self.ip_addr)
class GroupMsg(Base):
__tablename__ = 'GroupMsg'
id = Column(Integer, primary_key=True)
groupname = Column(String(64), unique=True, nullable=False)
def __repr__(self):
return "<id=%s, groupname=%s>" % (self.id, self.groupname)
基本的多對多的操做:
Base.metadata.create_all(engine) # 建立全部的表結構
if __name__ == '__main__': SessionCls = sessionmaker(bind=engine) session = SessionCls() # 鏈接的實例
# =================== 建立組 =======================
# g1 = GroupMsg(groupname='g1')
# g2 = GroupMsg(groupname='g2')
# g3 = GroupMsg(groupname='g3')
# g4 = GroupMsg(groupname='g4')
# g5 = GroupMsg(groupname='g5')
# session.add_all([g1, g2, g3, g4, g5])
# =================== 建立主機 =======================
# h1 = HostMsg(hostname='host1', ip_addr='172.16.172.1', prot=55)
# h2 = HostMsg(hostname='host2', ip_addr='172.16.172.2', prot=56)
# h3 = HostMsg(hostname='host3', ip_addr='172.16.172.3', prot=57)
# h4 = HostMsg(hostname='host4', ip_addr='172.16.172.4', prot=58)
# session.add_all([h1, h2, h3, h4])
# 根據對象,在建立主機時就肯定主機組
# g3 = session.query(GroupMsg).filter(GroupMsg.groupname == 'g3').first()
# g5 = session.query(GroupMsg).filter(GroupMsg.groupname == 'g5').first()
# h5 = HostMsg(hostname='host5', ip_addr='172.16.172.5', prot=58, group=[g3,g5])
# =================== 建立多對多關聯 =======================
# all_groups = session.query(GroupMsg).all() # 獲取全部的主機
# h2 = session.query(HostMsg).filter(HostMsg.hostname == 'host2').first() # 獲取其中一臺主機
# h2.group = all_groups
# g2 = session.query(GroupMsg).filter(GroupMsg.groupname == 'g2').first() # 獲取一個組名
g3 = session.query(GroupMsg).filter(GroupMsg.groupname == 'g3').first() h3 = session.query(HostMsg).filter(HostMsg.hostname == 'host3').first() # 獲取其中一臺主機
# h3.group = [g2, g3]
# 查看組包含的主機 主機所屬的組
print "------------------>g3:", g3.host_list print "------------------>h3:", h3.group session.commit()