ORM sqlachemy學習

內容: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人的共同點)

如今各類ORM框架都在嘗試使用各類方法來減輕這塊(LazyLoad,Cache),效果仍是很顯著的。

 

 

2.SQLAlchemy介紹

(1)什麼是SQLAlchemy

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

 

(2)SQLAlchemy原理

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

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)

 

 

最後內容 - 今日做業:

主題:學員管理系統

需求:

  • 用戶角色,講師\學員, 用戶登錄後根據角色不一樣,能作的事情不一樣,分別以下
  • 講師視圖
    1.   管理班級,可建立班級,根據學員qq號把學員加入班級
    2.   可建立指定班級的上課紀錄,注意一節上課紀錄對應多條學員的上課紀錄, 即每節課都有整班學員上, 爲了紀錄每位學員的學習成績,需在建立每節上課紀錄是,同時         爲這個班的每位學員建立一條上課紀錄
    3.   爲學員批改爲績, 一條一條的手動修改爲績
  • 學員視圖
  1. 提交做業
  2. 查看做業成績
  3. 一個學員能夠同時屬於多個班級,就像報了Linux的同時也能夠報名Python同樣, 因此提交做業時需先選擇班級,再選擇具體上課的節數
  4. 附加:學員能夠查看本身的班級成績排名
相關文章
相關標籤/搜索