一、寫在前面
其實之前已經寫過一篇關於 Flask 中使用數據庫的博客了,不過那一篇博客主要是記錄我在使用 Flask + MySQL8.0 時所遇到的一些問題(如果用的不是 MySQL8.0估計就沒有這么多問題了!)。然后這一篇可以算作一份學習筆記了,也是關於在 Flask 中進行數據庫操作的,感覺寫這種學習筆記還是比較有用的,可以再學習一遍也就能更好的掌握了。
在使用 Flask 的時候,一般都會創建一個 model.py,然后在里面繼承和創建模型,再遷移到數據庫中,最后進行一些增刪改查等操作。但是如果數據庫表已經建立好了呢?有沒有辦法將這些數據庫表引入到 Flask 中呢?
二、sqlacodegen
1.sqlacodegen簡介
sqlacodegen pypi:https://pypi.org/project/sqlacodegen/。
其中對 sqlacodegen 的介紹是:這是一個工具,它讀取現有數據庫的結構並生成相應的 SQLAlchemy 模型代碼,如果可能,使用聲明式樣式。
sqlacodegen 的幾個主要特性為:
1)支持 SQLAlchemy 0.8.x - 1.3.x。
2)生成幾乎看起來像是手寫的聲明性代碼。
3)生成符合 PEP 8 標准的代碼。
4)准確地確定關系,包括多對多,一對一。
5)自動檢測連接表繼承。
2.sqlacodegen安裝
使用 pip 安裝即可:
pip install sqlacodegen
3.sqlacodegen用法
下面是一個 sqlacodegen 用法示例:
sqlacodegen mysql+pymysql://root:qwer1234@127.0.0.1/mydb --tables users,roles,phone >models.py
首先是一個 sqlacodegen 命令,后面接上連接數據庫的語句,然后可以使用 --tables 指定要導入的數據表,最后用 >models.py 輸出到 models.py 中,如果不指定輸出文件,會將 python 代碼直接打印出來。下面是生成的 models.py 中的代碼:
1 # coding: utf-8 2 from sqlalchemy import Column, ForeignKey, String 3 from sqlalchemy.dialects.mysql import INTEGER 4 from sqlalchemy.orm import relationship 5 from sqlalchemy.ext.declarative import declarative_base 6 7 Base = declarative_base() 8 metadata = Base.metadata 9 10 11 class Phone(Base): 12 __tablename__ = 'phone' 13 14 phone = Column(String(11), primary_key=True) 15 phone_address = Column(String(40)) 16 17 18 class Role(Base): 19 __tablename__ = 'roles' 20 21 role_id = Column(INTEGER(11), primary_key=True) 22 role_name = Column(String(45)) 23 24 25 class User(Base): 26 __tablename__ = 'users' 27 28 user = Column(String(10), primary_key=True) 29 sex = Column(String(10)) 30 email = Column(String(45)) 31 phone = Column(String(11)) 32 role_id = Column(ForeignKey('roles.role_id'), index=True) 33 34 role = relationship('Role')
三、SQL Alchemy
1.SQL Alchemy簡介
SQL Alchemy pypi:https://pypi.org/project/SQLAlchemy/。
SQL Alchemy 是 Python SQL 工具包和對象關系映射器,它為應用程序開發人員提供了SQL的全部功能和靈活性。
在寫上篇博客的時候簡單介紹過 Flask-SQLAlchemy,當時說到它將對 SQL Alchemy 的支持添加到 Flask 應用程序中,因此我們通過簡單設置之后就能在 Flask 中隊數據庫進行操作了,可那是當我們在把定義好的模型映射到數據庫中時所用的。如果數據庫表已經建好了,還怎么用 Flask-SQLAlchemy 來操作呢?這時候就需要使用 SQL Alchemy 了!
2.SQL Alchemy安裝
使用 pip 安裝即可:
pip install SQLAlchemy
3.SQL Alchemy架構
1)Schema / Types
定義了類到表之間的映射框架(規則)。
2)SQL Expression Language
封裝好的 SQL 語句。
3)Engine
操作者。
4)Connection Pooling
連接池。
5)Dialect
根據用戶的配置,調用不同的數據庫 API(如:Mysql) 並執行對應的 SQL 語句。
4.SQL Alchemy用法
(1)連接數據庫
1 from sqlalchemy import create_engine 2 3 4 engine = create_engine("mysql+pymysql://root:qwer1234@127.0.0.1:3306/mydb")
create_engine() 會返回一個引擎實例,它代表着數據庫的接口。這個引擎實例可以執行 SQL 語句,例如:
engine.execute("show tables")
(2)創建會話
光有這個數據庫的引擎還不夠,還需要建立會話才行,這里要使用引擎來創建一個 Session 類的實例,代碼為:
1 from sqlalchemy import create_engine 2 from sqlalchemy.orm import sessionmaker 3 4 5 # 創建引擎 6 engine = create_engine("mysql+pymysql://root:qwer1234@127.0.0.1:3306/mydb") 7 # 使用引擎創建Session 8 DB_Session = sessionmaker(bind=engine) 9 # 實例化 10 db_session = DB_Session()
(3)單表 CRUD
插入數據:
1 # 插入 2 db_session.execute("insert into roles values(%d,%s)" % (1, "'admin'")) 3 db_session.execute("insert into users values(%s,%s,%s,%s,%d)" % ("'user1'", "'man'", "'user1@163.com'", "'12233445566'", 1)) 4 db_session.commit()
插入數據可以使用 SQL 語句來完成,在插入數據之后要使用 commit(),這一點不能忘記。
查詢數據:
1 # 查詢 2 result = db_session.query(User).filter(User.user == "user1") 3 print(result.all()) 4 usr = result.all()[0] 5 print(usr.email) 6 7 # [<SQlAlchemy.models.User object at 0x0000028D33D7CDD8>] 8 # user1@163.com
在查詢的時候需要使用 query() 和 filter(),返回的結果是一個列表,如果列表為空就表示數據庫中沒有該記錄。對於返回的這個結果,使用 all() 返回所有記錄,使用 one() 返回第一條記錄。
更新數據:
1 # 更新 2 db_session.query(User).filter(User.user == "user1").update({User.email: 'user1user1@163.com'}) 3 db_session.commit() 4 # 查詢 5 result = db_session.query(User).filter(User.user == "user1") 6 usr = result.one() 7 print(usr.email) 8 9 # user1user1@163.com
更新數據可以使用 update() 方法,不過要接在 filter() 之后,使用這種方法即使數據庫中沒有記錄也不會報錯。
刪除數據:
1 # 刪除 2 db_session.query(User).filter(User.user == "user1").delete() 3 # 查詢 4 result = db_session.query(User).filter(User.user == "user1") 5 usr = result.one() 6 print(usr.email) 7 8 # sqlalchemy.orm.exc.NoResultFound: No row was found for one()
刪除數據的使用方法和更新數據類似,只不過是在 filter() 之后使用 delete() 方法。
(4)多表查詢
假設要查詢 phone 為"12233445566"的用戶名稱和電話所在地址,就需要將 users 表和 phone 表聯合起來進行查詢,方法是使用多個 filter():
1 res = db_session.query(User, Phone).filter(User.phone == "12233445566").filter(Phone.phone == "12233445566") 2 u, p = res.one() 3 print(u.user, p.phone_address) 4 5 # user1 A
假設要查詢 user 為"user1"的用戶的角色信息,就需要將 users 表和 roles 表聯合起來進行查詢,因為有外鍵的關系,所以可以使用 join():
1 res = db_session.query(User).join(Role).filter(User.user == "user1") 2 u = res.one() 3 print(u.user, u.role.role_name) 4 5 # user1 admin