內容:html
1.ORM介紹python
2.SQLAlchemy介紹mysql
3.SQLAlchemy內部處理sql
4.SQLAlchemy使用數據庫
參考:編程
http://www.cnblogs.com/wupeiqi/articles/5713330.htmlsession
http://www.cnblogs.com/alex3714/articles/5978329.html數據結構
廖雪峯SQLAlchemy教程 oracle
1.ORM介紹app
ORM(object relational mapping),就是對象映射關係,簡單來講:
對於python而已一切皆對象,可是咱們使用的數據庫卻都是關係型的,爲了保證一致的使用習慣,經過ORM將編程語言的對象模型和數據庫的關係模型創建映射關係,這樣咱們在使用編程語言對數據庫進行操做的時候能夠直接使用編程語言的對象模型(類和對象)進行操做就能夠了,而不用直接使用sql語言。
ORM優勢:
ORM缺點:
無可避免的,自動化意味着映射和關聯管理,代價是犧牲性能(早期,這是全部不喜歡ORM人的共同點)
如今各類ORM框架都在嘗試使用各類方法來減輕這塊(LazyLoad,Cache),效果仍是很顯著的。
2.SQLAlchemy介紹
(1)什麼是SQLAlchemy
SQLAlchemy是Python編程語言下的一款ORM框架,該框架創建在數據庫API之上,使用關係對象映射進行數據庫操做,簡言之即是:將對象轉換成SQL,而後使用數據API執行SQL並獲取執行結果。
(2)SQLAlchemy原理
數據庫表是一個二維表,包含多行多列。把一個表的內容用Python的數據結構表示出來的話,能夠用一個list表示多行,list的每個元素是tuple,表示一行記錄,好比,包含id
和name
的user
表:
1 [ 2 ('1', 'woz'), 3 ('2', 'wyb'), 4 ('3', 'alex') 5 ]
Python的DB-API返回的數據結構就是像上面這樣表示的,可是用tuple表示一行很難看出表的結構。
若是把一個tuple用class實例來表示,就能夠更容易地看出表的結構來:
1 class User(object): 2 def __init__(self, id, name): 3 self.id = id 4 self.name = name 5 6 [ 7 User('1', 'wyb'), 8 User('2', 'woz'), 9 User('3', 'alex') 10 ]
這就是傳說中的ORM技術:Object-Relational Mapping,就是把關係數據庫的表結構映射到類的對象上
可是由誰來作這個轉換呢?由專業的ORM框架來作轉換,Python中最有名的ORM框架是SQLAlchemy
(3)安裝
1 pip3 install SQLAlchemy
3.SQLAlchemy內部處理
(1)依賴第三方
SQLAlchemy自己沒法操做數據庫,其必須以來pymsql等第三方插件,Dialect用於和數據API進行交流,根據配置文件的不一樣調用不一樣的數據庫API,從而實現對數據庫的操做,如:
1 MySQL-Python (py2語法) 2 mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> 3 4 pymysql (py3語法) 5 mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] 6 7 MySQL-Connector 8 mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> 9 10 cx_Oracle 11 oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 12 13 更多詳見:http://docs.sqlalchemy.org/en/latest/dialects/index.html
(2)內部處理
使用 Engine/ConnectionPooling/Dialect 進行數據庫操做,Engine使用ConnectionPooling鏈接數據庫,而後再經過Dialect執行SQL語句
4.SQLAlchemy使用
SQLAlchemy的使用本質上就是對其ORM功能的使用,詳細說就是使用 ORM/Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 全部組件對數據進行操做。根據類建立對象,對象轉換成SQL,執行SQL
(1)建立表
建立一個表(user)並插入數據:
1 # __author__ = "wyb" 2 # date: 2018/8/20 3 from sqlalchemy.ext.declarative import declarative_base 4 from sqlalchemy.orm import sessionmaker 5 from sqlalchemy import ( 6 create_engine, 7 Column, 8 Integer, 9 String, 10 ) 11 12 # create_engine相似pymysql中的connect 13 # 設置echo將打印一系列過程信息 14 engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/wyb", 15 encoding="utf-8", 16 echo=True, 17 max_overflow=5) 18 19 Base = declarative_base() # 生成ORM基類 20 21 22 # 接下來建立一個User表 23 class User(Base): 24 __tablename__ = 'user' # 表名 25 id = Column(Integer, primary_key=True) 26 name = Column(String(32)) 27 password = Column(String(64)) 28 29 30 Base.metadata.create_all(engine) # 建立表結構 31 32 33 # 接下來對錶中數據進行操做 34 # 建立與數據庫的會話session class ,注意,這裏返回給session的是個class,不是實例 35 Session_class = sessionmaker(bind=engine) 36 Session = Session_class() # 生成session實例(相似pymysql中的cursor) 37 38 # 生成數據對象(未建立,commit以後才建立) 39 user_obj = User(name="wyb", password="666") 40 user_obj2 = User(name="woz", password="3399") 41 Session.add(user_obj) # 把數據對象添加到session裏, 後面統一建立 42 Session.add(user_obj2) # 把數據對象添加到session裏, 後面統一建立 43 Session.commit() # 現此統一提交,建立數據
(2)操做表(增刪改查)
1 # __author__ = "wyb" 2 # date: 2018/8/20 3 from sqlalchemy.ext.declarative import declarative_base 4 from sqlalchemy.orm import sessionmaker 5 from sqlalchemy import ( 6 create_engine, 7 Column, 8 Integer, 9 String, 10 ) 11 12 # create_engine相似pymysql中的connect 13 # 設置echo將打印一系列過程信息 14 engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/wyb", 15 encoding="utf-8", 16 # echo=True, 17 max_overflow=5) 18 19 Base = declarative_base() # 生成ORM基類 20 Session_class = sessionmaker(bind=engine) # 建立session類 21 Session = Session_class() # 生成session實例(相似pymysql中的cursor) 22 23 24 # 接下來建立一個User表 25 class User(Base): 26 __tablename__ = 'user' # 表名 27 id = Column(Integer, primary_key=True) 28 name = Column(String(32)) 29 password = Column(String(64)) 30 31 # 直接輸出查詢結果 32 # __repr__是魔法方法 當直接輸出User對象的實例會調用此方法 33 def __repr__(self): 34 return "<User(id='%s', name='%s', password='%s')>" % ( 35 self.id, self.name, self.password) 36 37 38 # 建立表結構 39 def create_table(): 40 Base.metadata.create_all(engine) 41 42 43 # 插入 44 def insert(user_obj): 45 print("插入數據:") 46 print(user_obj) 47 Session.add(user_obj) # 把數據對象添加到session裏, 後面統一建立 48 Session.commit() # 現此統一提交,建立數據 49 50 51 # 查找 52 def select(): 53 print("查詢數據:") 54 55 # 查詢一條數據: 56 data = Session.query(User).filter_by(name="woz").first() # 不存在返回None 57 print("name=woz: ", data) 58 data = Session.query(User).filter_by(id=1).first() 59 print("id=1: ", data) 60 # print(my_user.id, my_user.name, my_user.password) # 輸出具體值 61 62 # 查詢全部數據: 63 print("表中全部數據: ", Session.query(User.id, User.name).all()) 64 65 # 多條件查詢: 66 objs = Session.query(User).filter(User.id > 0).filter(User.id < 3).all() 67 # 上面2個filter的關係至關於 user.id >1 AND user.id <3 的效果 68 print("id爲0到3之間的數據: ", objs) 69 70 71 # 刪除 72 def delete(): 73 print("刪除數據:") 74 result = Session.query(User).filter(User.name == 'alex').first() 75 print(result) 76 Session.delete(result) 77 Session.commit() 78 79 80 # 更新 81 def update(): 82 print("更新數據:") 83 my_user = Session.query(User).filter_by(name="wyb").first() 84 my_user.name = "wyb666" 85 my_user.password = "wyb666" 86 print(my_user) 87 Session.commit() 88 89 90 # 主程序 91 def main(): 92 create_table() 93 # 插入數據: 94 # insert(User(name="alex", password="3373")) 95 # 查詢數據: 96 # select() 97 # update() 98 # delete() 99 100 101 if __name__ == '__main__': 102 main()
(3)回滾以及統計分組
回滾:
1 my_user = Session.query(User).filter_by(id=1).first() 2 my_user.name = "Jack" 3 4 fake_user = User(name='Rain', password='12345') 5 Session.add(fake_user) 6 7 print(Session.query(User).filter(User.name.in_(['Jack','rain'])).all() ) # 這時看session裏有你剛添加和修改的數據 8 Session.rollback() #此時你rollback一下 9 print(Session.query(User).filter(User.name.in_(['Jack','rain'])).all() ) # 再查就發現剛纔添加的數據沒有了。 10 11 # Session.commit()
統計分組:
1 # 統計: 2 Session.query(User).filter(User.name.like("w%")).count() 3 4 # 分組 5 from sqlalchemy import func 6 print(Session.query(func.count(User.name),User.name).group_by(User.name).all() ) 7 # 至關於如下原生SQL: 8 SELECT count(user.name) AS count_1, user.name AS user_name 9 FROM user GROUP BY user.name
(4)外鍵關聯
外鍵關聯:
1 from sqlalchemy.ext.declarative import declarative_base 2 from sqlalchemy.orm import sessionmaker, relationship 3 from sqlalchemy import ( 4 create_engine, 5 Column, 6 Integer, 7 String, 8 ForeignKey, 9 ) 10 11 engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/wyb", 12 encoding="utf-8", 13 max_overflow=5) 14 15 Base = declarative_base() # 生成ORM基類 16 Session_class = sessionmaker(bind=engine) # 建立session類 17 Session = Session_class() # 生成session實例(相似pymysql中的cursor) 18 19 # User表 20 class User(Base): 21 __tablename__ = 'user' 22 id = Column(Integer, primary_key=True) 23 name = Column(String(32)) 24 password = Column(String(64)) 25 26 def __repr__(self): 27 return "<User(id='%s', name='%s', password='%s')>" % ( 28 self.id, self.name, self.password) 29 30 31 # Address表 32 class Address(Base): 33 __tablename__ = 'address' 34 id = Column(Integer, primary_key=True) 35 email_address = Column(String(32), nullable=False) 36 user_id = Column(Integer, ForeignKey('user.id')) # 這是外鍵 37 38 user = relationship("User", backref="address") # 這個nb,容許你在user表裏經過backref字段反向查出全部它在addresses表裏的關聯項 39 40 def __repr__(self): 41 return "<Address(email_address='%s')>" % self.email_address 42 43 # 建立表結構 44 def create_table(): 45 Base.metadata.create_all(engine)
上述表建立好後,能夠這樣反查:
1 objs = Session.query(User).all() 2 add_objs = Session.query(Address).all() 3 for i in objs: # 經過遍歷user對象反查關聯的address記錄 4 print(i.address) 5 for add_obj in add_objs: # 遍歷add_objs裏直接查關聯的user對象 6 print(add_obj.user.name)
建立關聯對象:
1 obj = Session.query(User).filter(User.name == 'woz').first() 2 # 查詢關聯對象的屬性: 3 print(obj.address) 4 # 添加關聯對象: 5 obj.address = [Address(email_address="wyb@126.com")] 6 Session.commit()
多外鍵關聯:
下表中,Customer表有2個字段都關聯了Address表
1 class Address(Base): 2 __tablename__ = 'address' 3 id = Column(Integer, primary_key=True) 4 street = Column(String) 5 city = Column(String) 6 state = Column(String) 7 8 class Customer(Base): 9 __tablename__ = 'customer' 10 id = Column(Integer, primary_key=True) 11 name = Column(String) 12 13 billing_address_id = Column(Integer, ForeignKey("address.id")) 14 shipping_address_id = Column(Integer, ForeignKey("address.id")) 15 16 # 這樣寫 會致使SQLAlchemy分不清哪一個外鍵是對應哪一個字段 會致使程序報錯 17 # billing_address = relationship("Address") 18 # shipping_address = relationship("Address") 19 20 # 因此要這樣寫: 21 billing_address = relationship("Address", foreign_keys=[billing_address_id]) 22 shipping_address = relationship("Address", foreign_keys=[shipping_address_id])
(5)多對多聯繫
什麼是多對多聯繫:學生和課程,一個課程能夠有多個學生,一個學生能夠有多個課程
以下所示:
1 # 多對多 2 # 一個學生能夠有多個課程,一個課程能夠對應多個學生 3 student_m2m_course = Table('student_m2m_course', Base.metadata, 4 Column('student_id', Integer, ForeignKey('student.id')), 5 Column('author_id', Integer, ForeignKey('course.id')), 6 ) 7 8 # 學生類 9 class Student(Base): 10 __tablename__ = 'student' 11 id = Column(Integer, primary_key=True) 12 name = Column(String(64)) 13 attach = relationship('Attach', secondary=student_m2m_course, backref='students') 14 15 def __repr__(self): 16 return "<name: %s;>" % self.name 17 18 # 課程類 19 class Course(Base): 20 __tablename__ = 'course' 21 id = Column(Integer, primary_key=True) 22 name = Column(String(32)) 23 24 def __repr__(self): 25 return "<name: %s;>" % self.name
具體操做:
1 # 關聯插入 2 a1 = Student(name="12342ds") 3 a2 = Student(name="222") 4 a3 = Student(name="666") 5 6 b1 = Course(name="跟wyb學Python") 7 b2 = Course(name="跟wyb學把妹") 8 b3 = Course(name="跟wyb學裝逼") 9 b4 = Course(name="跟wyb學開車") 10 11 a1.courses = [b1, b2] 12 a2.courses = [b2, b3] 13 a3.courses = [b1, b3] 14 15 Session.add_all([a1, a2, a3, b1, b2, b3, b4]) 16 Session.commit() 17 18 19 # 多對多刪除 20 # 刪除數據時不用管student_m2m_course這個表, sqlalchemy會自動幫你把對應的數據刪除 21 student_obj = Session.query(Student).filter_by(name="12342ds").first() 22 23 course_obj = Session.query(Course).filter_by(name="跟wyb學把妹").first() 24 print(student_obj, course_obj) 25 # 如下是兩種刪除方法: 26 student_obj.courses.remove(course_obj) # 從課程中裏刪除一個學生 27 Session.delete(course_obj ) # 直接刪除課程時會把這個課程和全部學生的關聯關係刪除 28 Session.commit()
(6)其餘
處理中文:
sqlalchemy設置編碼字符集必定要在數據庫訪問的URL上增長charset=utf8,不然數據庫的鏈接就不是utf8的編碼格式
eng = create_engine('mysql://root:root@localhost:3306/test2?charset=utf8',echo=True)
最後內容 - 今日做業:
主題:學員管理系統
需求: