ORM 對象映射關系程序。
通過orm將編程語言的對象模型和數據庫的關系模型建立映射關系,這樣我們在使用編程語言對數據庫進行操作的時候可以直接使用編程語言的對象模型進行操作就可以了,而不用直接使用sql語言。
orm的優點:
- 隱藏了數據訪問細節,“封閉”的通用數據庫交互,ORM的核心。他使得我們的通用數據庫交互變得簡單易行,並且完全不用考慮該死的SQL語句。快速開發,由此而來。
- ORM使我們構造固化數據結構變得簡單易行。
缺點:
- 無可避免的,自動化意味着映射和關聯管理,代價是犧牲性能(早期,這是所有不喜歡ORM人的共同點)。現在的各種ORM框架都在嘗試使用各種方法來減輕這塊(LazyLoad,Cache),效果還是很顯著的。
最有名的ORM框架是SQLAlchemy,系統中沒有該模塊的需要安裝 pip install sqlalchemy (或easy_install SQLAlchemy)
如果在pip install sqlalchemy 中報ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org'錯,需要先設置超時時間:pip --default-timeout=100 install -U Pillow,再重新安裝 pip install sqlalchemy,通過imort sqlalchemy驗證是否安裝正常。
ORM框架SQLAlchemy 使用,創建表:
#conding:utf-8 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String #區分大小寫 #創建連接 engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True) #生成orm基類 base=declarative_base() class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64)) base.metadata.create_all(engine) #創建表結構
注:pymysql設置編碼字符集一定要在數據庫訪問的URL上增加?charset=utf8,否則數據庫的連接就不是utf8的編碼格式
engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True)
ORM框架SQLAlchemy 使用,插入數據:
#conding:utf-8 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String #區分大小寫 from sqlalchemy.orm import sessionmaker #創建連接 engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True) #生成orm基類 base=declarative_base() class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64)) base.metadata.create_all(engine) #創建表結構 Session_class=sessionmaker(bind=engine) ##創建與數據庫的會話,class,不是實例 Session=Session_class() #生成session實例 user_obj = user(name="rr",password="123456") #插入你要創建的數據對象,每執行一次都會新增一次數據。 print user_obj.name,user_obj.id #此時還沒創建對象呢,不信你打印一下id發現還是None Session.add(user_obj) #把要創建的數據對象添加到這個session里 print user_obj.name,user_obj.id #此時也依然還沒創建 Session.commit() #提交,使前面修改的數據生效。
結果:
查詢:
my_user = Session.query(user).filter_by(name="ee").first() #創建查詢對象 print(my_user.id,my_user.name,my_user.password) #輸出查詢內容 print my_user #內存地址
結果:
修改:
my_user = Session.query(user).filter_by(name="yy").first() #根據指定條件創建符合條件的對象 my_user.name='uu' #將name='yy'的name修改為uu print(my_user.id,my_user.name,my_user.password) #輸出查詢內容
結果:
參考數據表:
回滾:
user_obj = user(name="kk",password="99999") #插入你要創建的數據對象 Session.add(user_obj) #把要創建的數據對象添加到這個session里 my_user = Session.query(user).filter_by(name="rr").first() #根據指定條件創建符合條件的對象,first()是指name='rr'的第一條記錄 my_user.name="gg" #將name='yy'的name修改為uu print(Session.query(user).filter(user.name.in_(["gg","kk"])).all()) #顯示修改后的數據 Session.rollback() #回滾 print(Session.query(user).filter(user.name.in_(["gg","kk"])).all()) #顯示回滾后的內容
結果:
獲取所有數據
print Session.query(user.id,user.name).all() #只顯示id,name
結果:
多條件查詢
objs = Session.query(user).filter(user.id>0).filter(user.id<=3).all() #注意:filter()中的關鍵字不能是表達式user.id=0 print objs
filter的關系相當於 user.id >0 AND user.id <=3 的效果
結果:
統計和分組
objs = Session.query(user).filter(user.name.like('r%')).count() #統計 print objs
結果:
from sqlalchemy import func print(Session.query(func.count(user.name),user.name).group_by(user.name).all() ) #分組
結果:
外鍵關聯
參照表:兩張表是一對多的關系。
users(一)
addresses(多)
創建表addresses,將users表中的id作為addresses表的外鍵。
import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String,ForeignKey #區分大小寫 from sqlalchemy.orm import sessionmaker,relationship #創建連接 engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True) #生成orm基類 base=declarative_base() class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64)) def __repr__(self): return "<user(id='%d',name='%s', password='%s')>" % (self.id, self.name, self.password) class Address(base): __tablename__ = 'addresses' id = Column(Integer, primary_key=True) email_address = Column(String(32), nullable=False) user_id = Column(Integer, ForeignKey('users.id')) user = relationship("user", backref="addresses") '''允許你在user表里通過backref字段反向查出所有它在addresses表里的關聯項,在內存中創建。在addresses表中可以使用user來查詢users表中的數據,在users表中可以使用backref后的addresses來查詢assresses表中的數據。''' def __repr__(self): return "<Address(email_address='%s',id='%d',user_id='%d')>" % (self.email_address,self.id,self.user_id) base.metadata.create_all(engine) #創建表結構 Session_class=sessionmaker(bind=engine) #創建與數據庫的會話,class,不是實例 Session=Session_class() #生成session實例 obj = Session.query(user).first() print obj.addresses #在users表里面通過addresses來查詢addresses表中的數據。 for i in obj.addresses: print i addr_obj = Session.query(Address).first() print(addr_obj.user) #在addresses表中通過user來查詢users表中的數據。 print(addr_obj.user.name) Session.commit() #提交,使前面修改的數據生效。
結果:
輸出的結果1是列表形式,print 多行記錄時以列表的形式顯示。
注:在定義表的類下面加 def
__repr__(
self
):
return ... 是為了在print時輸出哪些數據,以及輸出后的顯示形式。
補充:1.主鍵:是唯一標識一條記錄,不能有重復的,不允許為空,用來保證數據完整性
2.外鍵:是另一表的主鍵, 外鍵可以有重復的, 可以是空值,用來和其他表建立聯系用的。所以說,如果談到了外鍵,一定是至少涉及到兩張表。例如下面這兩張表:
設定條件向指定表中添加記錄:
obj = Session.query(user).filter(user.name=='ee').all()[0] #設定條件 print(obj.addresses) obj.addresses = [Address(email_address="ertttt"), #向addresses表中添加2列。 Address(email_address="dddd")]
結果:
多外鍵關聯
在Customer表有2個字段都關聯了Address表
class Customer(base): __tablename__ = 'customer' id = Column(Integer, primary_key=True) name = Column(String) billing_address_id = Column(Integer, ForeignKey("address.id")) shipping_address_id = Column(Integer, ForeignKey("address.id")) '''#創建的列billing_address_id、shipping_address_id都作為外鍵關聯address表中id列''' billing_address = relationship("Address") shipping_address = relationship("Address")#創建兩個關聯項 class Address(base): __tablename__ = 'address' id = Column(Integer, primary_key=True) street = Column(String) city = Column(String) state = Column(String)
如果報錯:
sqlalchemy.exc.AmbiguousForeignKeysError: Could
not
determine join
condition between parent
/
child tables on relationship
Customer.billing_address
-
there are multiple foreign key
illing_address = relationship("Address", foreign_keys=[billing_address_id]) shipping_address = relationship("Address", foreign_keys=[shipping_address_id])
使pymysql分清哪個外鍵是對應哪個字段。
多對多關系
from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True) base = declarative_base() book_m2m_author = Table('book_m2m_author', base.metadata, Column('book_id',Integer,ForeignKey('books.id')), Column('author_id',Integer,ForeignKey('authors.id')), ) #創建book_m2m_author表,關聯另外兩張表。 class Book(base): __tablename__ = 'books' id = Column(Integer,primary_key=True) name = Column(String(64)) pub_date = Column(DATE) authors = relationship('Author',secondary=book_m2m_author,backref='books') def __repr__(self): return self.name class Author(base): __tablename__ = 'authors' id = Column(Integer, primary_key=True) name = Column(String(32)) def __repr__(self): return self.name base.metadata.create_all(engine) #創建表結構 Session_class=sessionmaker(bind=engine) #創建與數據庫的會話,class,不是實例 Session=Session_class() b1 = Book(name="跟A學Python") b2 = Book(name="跟A學linux") b3 = Book(name="跟A學java") b4 = Book(name="跟C學開發") a1 = Author(name="A") a2 = Author(name="B") a3 = Author(name="C") b1.authors = [a1,a2] #建立關系 b2.authors = [a1,a2,a3] Session.add_all([b1,b2,b3,b4,a1,a2,a3]) Session.commit()
結果:
用orm查一下數據
book_obj = Session.query(Book).filter_by(name="跟A學Python").first() print(book_obj.name, book_obj.authors)#這里book_obj.authors只輸出name,因為定義類Author時在__repr__(self):定義了返回值 author_obj =Session.query(Author).filter_by(name="A").first() print(author_obj.name , author_obj.books)
結果:
多對多刪除
1.通過書刪除作者,刪除的是關系。
author_obj =Session.query(Author).filter_by(name="C").first() book_obj = Session.query(Book).filter_by(name="跟A學linux").first() book_obj.authors.remove(author_obj) #通過指定書里刪除作者,刪除的是關系,作者不受影響。
2.刪除作者的同時也刪除關系。
author_obj =Session.query(Author).filter_by(name="A").first() Session.delete(author_obj) #delete刪除作者A,關系也會刪除掉。
結果:
books表
authors表

book_m2m_author表