當(dāng)我們習(xí)慣 Flask-SQLAlchemy 對數(shù)據(jù)庫進(jìn)行 CRUD 操作后,就很難再回到基于原生 SQL 的代碼編寫了。
我們先來看 Read 操作。用實際的例子來說明用法,數(shù)據(jù)還是之前經(jīng)常用到的 emp_master ,
基于上一篇 Flask 工程的文件結(jié)構(gòu),在 models.py 中定義的 Class 如下:
class EmpMaster(db.Model):
emp_id = db.Column(db.Integer, primary_key=True)
gender = db.Column(db.String(10), nullable=False)
age = db.Column(db.Integer)
email = db.Column(db.String(50))
phone_nr = db.Column(db.String(20))
education = db.Column(db.String(20))
marital_stat = db.Column(db.String(20))
nr_of_children = db.Column(db.Integer)
def __repr__(self):
return '<emp_master %r>' % 'id:{}'.format(self.emp_id)
查詢數(shù)據(jù)
查詢所有數(shù)據(jù)
from app.models import db, EmpMaster
print (EmpMaster.query.all())
EmpMaster.query 得到的是 BaseQuery 對象的實例,對于 BaseQuery 類,SQLAlchemy 提供了一些查詢方法用于獲得你想要的查詢對象,比如 all() 方法以 list (列表) 的形式返回所有的查詢結(jié)果。
根據(jù)主鍵查詢數(shù)據(jù)
get() 或 get_or_404() 方法根據(jù)主鍵來查詢數(shù)據(jù)。get() 方法返回 model 的實例,如果找不到,則返回 None;而 get_or_404() 則返回 Not found 的錯誤響應(yīng)。
EmpMaster.query.get(1001) # 1001 是主鍵
篩選/過濾數(shù)據(jù)
篩選過濾數(shù)據(jù)通過 filter_by() 或 filter() 方法。假設(shè)我們想查詢所有女性雇員,可以這樣做:
emps = EmpMaster.query.filter_by(gender='Female').all()
if len(emps) > 0:
for emp in emps:
print(emp.emp_id, emp.gender, emp.email, emp.education)
else:
print ('No data.')
filter_by() 方法返回的是 BaseQuery 對象實例,參數(shù)是關(guān)鍵字表達(dá)式 (keyword expression),可以多個字段,多個字段之間為 and 關(guān)系。比如要查詢所有女性,并且學(xué)歷為 Bachelor 的員工:
emps = EmpMaster.query.filter_by(gender='Female', education='Bachelor11').all()
if len(emps) > 0:
for emp in emps:
print(emp.emp_id, emp.gender, emp.email, emp.education)
else:
print ('No data.')
更為靈活的方式是通過 filter() 方法,與 filter_by() 方法不同的是,filter() 方法的參數(shù)是 SQL Expression。舉幾個例子來說明。
查找所有 education 為 Bachelor 的員工:
emps = EmpMaster.query.filter(EmpMaster.education == 'Bachelor').all()
for emp in emps:
print (emp)
如果用 filter_by() 方法,是這樣的:
emps = EmpMaster.query.filter_by(education='Bachelor').all()
看出區(qū)別來了吧。下表列示了常見條件的寫法。
| 條件 | 示例 |
|---|---|
| 等于 | query.filter(EmpMaster.education == 'Bachelor') |
| 不等于 | query.filter(EmpMaster.education != 'Bachelor') |
| LIKE | query.filter(EmpMaster.email.like('s%')) |
| IN | query.filter(EmpMaster.education.in_(['Master', 'Bachelor'])) |
| NOT IN | query.filter(~EmpMaster.education.in_(['Master', 'Bachelor'])) |
| IS NULL | query.filter(EmpMaster.education == None) |
| IS NOT NULL | query.filter(EmpMaster.education != None) |
AND 條件:
EmpMaster.query.filter(EmpMaster.gender=='Female', EmpMaster.education=='Bachelor')
# 或者
from sqlalchemy import and_
emps = EmpMaster.query.filter(
and_(EmpMaster.gender=='Female', EmpMaster.education=='Bachelor')).all()
OR 條件
from sqlalchemy import or_
emps = EmpMaster.query.filter(
or_(EmpMaster.marital_stat=='Single', EmpMaster.nr_of_children==0))
Create
SQLAlchemy 有一個 session 對象,代表臨時存儲區(qū),數(shù)據(jù)的變動提交到 session 后,需要調(diào)用 commit() 將修改提交到數(shù)據(jù)庫,或者 rollback() 撤銷未提交的修改。
from app.models import db, EmpMaster
from app import create_app
app = create_app()
new_emp = EmpMaster(
emp_id = 9001,
gender = 'Female',
age = 18,
email = 'test@qq.com',
phone_nr = '13800138000',
education = 'Master',
marital_stat = 'Single',
nr_of_children = 0
)
db.session.add(new_emp)
db.session.commit()
可以使用 add_all() 方法批量創(chuàng)建記錄:
emp1 = EmpMaster(...)
emp2 = EmpMaster(...)
db.session.add_all([emp1, emp2])
db.session.commit()
Update
Update 記錄需要先定位到某記錄,然后對需要的字段賦值后,然后調(diào)用 commit() 方法提交修改:
emp = EmpMaster.query.get(9001)
emp.email = 'e9001@qq.com'
db.session.commit()
Delete
Delete 記錄先定位到某記錄,然后調(diào)用 delete() 方法發(fā)送刪除指到 session,最后調(diào)用 commit() 將請求提交到數(shù)據(jù)庫。
emp = EmpMaster.query.get(9001)
db.session.delete(emp)
db.session.commit()