Flask 的 ORM 模型-應用
在上一個小節中,講解了 ORM 模型的基本概念,并給出一個最小的例子說明如何建立面向對象與關系數據庫之間的映射關系。本小節介紹了 SqlAlchemy 的相關 API,通過一個完整的例子,對 mysql 數據庫進行增、刪、改、查。
1. 功能概述
在本小節,編寫程序 app.py
,對一個名稱為 school 的數據庫進行增、刪、改、查,數據庫中存在一張表 students,包含的字段如下:
字段名 | 類型 | 描述 |
---|---|---|
sno | 整數 | 學號 |
name | 字符串 | 姓名 |
age | 整數 | 年齡 |
在上一個小節中,使用 mysql 的命令行創建表 students,在本節的例子中,為了展示 ORM 的功能,以編程的方式創建表 students。
2. 配置 SQLAlchemy
首先,引入相關庫,對訪問 mysql 進行配置,如下所示:
#!/usr/bin/python3
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import sys
app = Flask(__name__)
user = 'root'
password = '123456'
database = 'school'
uri = 'mysql+pymysql://%s:%s@localhost:3306/%s' % (user, password, database)
app.config['SQLALCHEMY_DATABASE_URI'] = uri
db = SQLAlchemy(app)
在第 1 行到第 4 行,引入庫 flask 和 flask_sqlalchemy;在第 6 行到第 11 行,對 SQLAlchemy 進行配置,設置如下參數:
參數 | 值 |
---|---|
user | 訪問數據庫的用戶,假設是 root |
password | 訪問數據庫的密碼,假設是 123456 |
database | 數據庫名稱 |
uri | SQLAlchemy 連接數據庫的字符串 |
在第 8 行,對 SQLAlchemy 進行配置,SQLALCHEMY_DATABASE_URI 配置的是連接數據庫的字符串,在這個例子中,該字符串為:
mysql+pymysql://root:123456@localhost:3306/school
字符串中的 “mysql+pymysql” 表示:數據庫類型是 mysql,使用 pymysql 作為訪問 mysql 的底層 API。
最后,在第 13 行,創建 SQLAlchemy 對象,用于映射數據庫表和對象。
3. 程序框架
程序包含有 4 個主要功能:
函數名 | 功能 |
---|---|
create_table | 創建表 students |
insert_students | 在表 students 中插入數據 |
query_students | 查詢表 students |
update_students | 更新表 students 中的數據 |
delete_students | 刪除表 students 中的數據 |
class Student(db.Model):
pass
def create_table():
pass
def insert_students():
pass
def query_students():
pass
def update_students():
pass
def delete_students():
pass
command = sys.argv[1]
if command == 'create':
create_table()
elif command == 'insert':
insert_students()
elif command == 'query':
query_students()
elif command == 'update':
update_students()
elif command == 'delete':
delete_students()
首先,定義繼承于 db.Model 的類 Student,該類映射數據庫中的表 students;然后,分別定義了實現上述功能的函數,在后續小節會陸續填充;最后,例子程序是一個命令行程序,根據不同的命令行參數調用相應的功能函數。
4. 創建表
class Student(db.Model):
__tablename__ = 'students'
sno = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
age = db.Column(db.Integer)
def dump(self):
print(self.sno, self.name, self.age)
def create_table():
db.drop_all()
db.create_all()
首先,建立表和類的映射關系:創建類 Student 繼承于 db.Model,表示類 Student 用于映射數據庫中的表;設定 __tablename__ 為 students,表示將類 Student 映射到數據庫中的表 students。
然后,建立屬性和字段的映射關系:映射 sno 到表 students 的字段 sno,類型為整數 (db.Integer),primary_key=True 表示該字段是主鍵; 映射 name 到表 students 的字段 name,類型為整數 (db.String); 映射 age 到表 students 的字段 age,類型為整數 (db.Integer)。
調用 db.drop_all() 刪除數據庫 school 中的所有表格;調用 db.create_all() 創建已經建立映射關系的表 students,表 students 已經被映射到類 Student。
5. 插入數據
def insert_students():
tom = Student(sno = 1, name = 'tom', age = 12)
db.session.add(tom)
db.session.commit()
jerry = Student(sno = 2, name = 'jerry', age = 11)
mike = Student(sno = 3, name = 'mike', age = 11)
db.session.add_all([jerry, mike])
db.session.commit()
在第 2 行,通過類 Student 實例化生成一個實例 tom,調用 db.session.add(tom) 將該實例加入到數據庫連接會話中,調用 db.session.commit() 提交保存到數據庫。
在第 6 行和第 7 行,生成 2 個實例 jerry 和 mike,調用 db.session.add_all([jerry, mike]) 將兩個實例批量加入到數據庫連接會話中,調用 db.session.commit() 提交保存到數據庫。
6. 查詢數據
完成查詢表 students 的函數 query_students,該函數包括 4 個片段:
6.1 查詢所有的學生
def query_students():
print('查詢所有的學生')
students = Student.query.all()
for student in students:
student dump()
print()
類 Student 繼承于類 db.Model,繼承了方法 db.Model.query.all(),該方法查詢表中所有的數據,無條件返回表中所有的數據。
類 Student 映射為表 students,Student.query.all() 返回表 students 中所有的學生數據。
6.2 指定條件查詢
繼續在函數 query_students 中增加如下代碼:
print('查詢所有年齡是 11 歲的學生')
students = Student.query.filter_by(age = 11)
for student in students:
student.dump()
print()
類 Student 繼承于類 db.Model,繼承了方法 db.Model.query.filter_by(conidtion),該方法的參數 condition 是查詢條件,返回表中符合條件的數據。
類 Student 映射為表 students,Student.filter_by(age = 11) 指明查詢條件為 age = 11, 返回表 students 中所有年齡是 11 歲的學生。
6.3 查詢第一個符合條件的數據
繼續在函數 query_students 中增加如下代碼:
print('查詢第一個年齡是 11 歲的學生')
students = Student.query.filter_by(age = 11)
student = students.first()
student.dump()
print()
方法 db.Model.query.filter_by(conidtion) 返回一個集合,包括所有滿足條件的數據。方法 first() 返回第一個符合條件的數據。
6.4 根據條件組合查詢
繼續在函數 query_students 中增加如下代碼:
print('查詢姓名是 jerry 并且年齡是 11 歲的學生')
students = Student.query.filter_by(age = 11, name = 'jerry')
for student in students:
student.dump()
print()
在方法 db.Model.query.filter_by(conidtion) 中,參數 condition 可以是多個。filter_by(age = 11, name = ‘jerry’) 表示查詢姓名是 jerry 并且年齡是 11 歲的學生。
7. 更新數據
def update_students():
students = Student.query.filter_by(name = 'tom')
students.update({'name':'TOM'})
db.session.commit()
類 Student 映射為表 students,Student.filter_by(name = ‘tom’) 指明查詢條件為 name = ‘tom’, 返回表 students 中所有姓名是 tom 的學生。
調用 update({‘name’: ‘TOM’}) 方法,將所有姓名是 tom 的學生的姓名更改為 TOM,調用 db.session.commit() 提交保存到數據庫。
8. 刪除數據
def delete_students():
students = Student.query.filter_by(name = 'mike')
students.delete()
db.session.commit()
類 Student 映射為表 students,Student.filter_by(name = ‘mike’) 指明查詢條件為 name = ‘mike’, 返回表 students 中所有姓名是 mike 的學生。
調用 delete() 方法,將所有姓名是 mike 的學生從表 students 中刪除,調用 db.session.commit() 提交保存到數據庫。
9. 測試程序
1. 在 mysql 命令行中創建數據庫 school
$ sudo mysql
mysql > drop database school;
mysql > create database school;
2. 創建表 students
$ python3 app.py create
3. 向表 students 插入數據
$ python3 app.py insert
4. 查詢表 students 中的數據
$ python3 app.py query
查詢所有的學生
1 tom 12
2 jerry 11
3 mike 11
查詢所有年齡是 11 歲的學生
2 jerry 11
3 mike 11
查詢第一個年齡是 11 歲的學生
2 jerry 11
查詢姓名是 jerry 并且年齡是 11 歲的學生
2 jerry 11
結果顯示,向數據庫中插入了 3 個學生:tom、jerry 和 mike。
5. 更新表 students 中的數據
$ python3 app.py update
$ python3 app.py query
查詢所有的學生
1 TOM 12
2 jerry 11
3 mike 11
...
結果顯示,姓名為 tom 的學生的姓名更改為 TOM。
6. 刪除表 students 中的數據
$ python3 app.py delete
$ python3 app.py query
查詢所有的學生
1 TOM 12
2 jerry 11
...
結果顯示,姓名為 mike 的學生被刪除。
5. 源代碼下載
6. 小結
本小節通過一個具體的實例講解了 SqlAlchemy 的相關 API,使用思維導圖概括如下:
通過本節的例子,可以看出,與拼接 SQL 語句訪問數據庫相比,通過 ORM 進行數據庫訪問,顯著的提高了代碼的可讀性。