Flask 的 ORM 模型 - 概述
在词条使用 Python 操作 MySQL 数据库中,通过 sql 语句访问数据库,繁琐易错。本小节介绍了用于简化访问数据库的 ORM 模型,ORM 模型定义了关系数据库和对象的映射关系,使得访问数据库的代码简单清晰、易于维护。
1. 问题的产生
访问关系数据库的传统方式是:拼接 sql 语句。例如,向数据库中插入一条数据,根据要插入的数据拼接一条 sql INSERT 语句,下面的 Python 程序使用 sql 语句向数据库中插入一条学生的信息:
sno = '20201916'
name = '张三'
age =
gender = 'male'
sql = 'INSERT INTO students(sno, name, age, gender) VALUES("%s", "%s", %d, "%s")' % (sno, name, age, gender)
rows = cursor.execute(sql)
INSERT INTO students(sno, name, age, gender) VALUES("", "张三", , "male");
1. 繁琐易错
在上面的例子中,第 5 行代码用于拼接 INSERT 语句,INSERT 语句需要插入 4 个字段,该行代码较长,无法在一行显示。在实际的软件开发中,INSERT 语句可能需要插入 10 个以上的字段,那么拼接 INSERT 语句的代码则非常的繁琐易错。
sql = "INSERT INTO Flights(FlightID, AircraftModel, RegisterID, Direction, ExpectApronTime, RunwayID, ApronID, AirwayID, TaxiwayTimes, AirwayTimes, Rank) VALUES('%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', %d)" % (flightID, aircraftModel, registerID, direction, expectApronTime, runwayID, apronID, airwayID, taxiwayTimes, airwayTimes, rank)
2. sql 语句重复利用率低
3. Web 安全漏洞
username = 从页面请求中获取用户名
password = 从页面请求中获取密码
sql = 'select * from users where username = "%s" and password = "%s"' % (username, password)
在第 3 行的 SELECT 语句中,where 条件进行权限检查,只有 username 和 password 与数据库表 users 中的数据匹配时,才返回有效数据,因此,只有用户输入正确的用户名和密码才可以获取数据。
这条 sql 语句存在有安全漏洞,假设用户在页面中输入的用户名为 admin"# (共 7 个字符,前 5 个字符是 admin,后面 2 个字符是 " 和 #),密码为 123456,则最终拼接的 sql 语句如下:
select * from users where username = "admin"#" and password = "123456"
select * from users where username = "admin"
2. 对象 - 关系映射 (ORM)
随着面向对象的软件开发方法发展,出现了对象 - 关系映射 (Object Relation Mapping) 模型,简称为 ORM,ORM 通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。
ORM 描述的对象关系映射如上图图所示:
CREATE TABLE students(
sno VARCHAR(),
name VARCHAR(),
age INT
);
class Student:
def __init__(self, sno, name, age):
self.sno = sno
self.name = name
self.age = age
tom = Student('1918001', 'tom', )
3. sqlAlchemy 简介
sqlAlchemy 是 Python 中一个通过 ORM 操作数据库的框架。sqlAlchemy 对象关系映射器提供了一种方法,用于将用户定义的 Python 类与数据库表相关联,并将这些类实例与其对应表中的行相关联。sqlAlchemy 可以让开发者使用类和对象的方式操作数据库,从而从繁琐的 sql 语句中解脱出来。
sqlAlchemy 的架构如下所示:
在 sqlAlchemy 的核心架构中,Schema / Types 定义了类到表之间的映射规则。DBAPI 是访问关系数据库的底层接口,底层接口仍然通过 sql 语句访问关系数据库。sqlAlchemy 支持多种关系数据库 (Oracle, Postgresql, MysqL),Dialect 根据用户的配置,调用不同的数据库底层访问 API,并执行对应的 sql 语句。
4. 使用 sqlAlchemy 完成映射
本小节讲解在 Flask 中使用 sqlAlchemy 完成表与对象的映射,分为如下步骤:
4.1 安装相关库
$ pip3 install flask
$ pip3 install pyMysqL
$ pip3 install sqlAlchemy
$ pip3 install flask-sqlalchemy
4.2 创建数据库
DROP DATABASE IF EXISTS school;
CREATE DATABASE school;
USE school;
CREATE TABLE students(
sno INT,
name VARCHAR(),
age INT,
PRIMARY KEY(sno)
);
INSERT students(sno, name, age) VALUES(, 'tom', );
INSERT students(sno, name, age) VALUES(, 'jerry', );
INSERT students(sno, name, age) VALUES(, 'mike', );
4.3 创建 sqlAlchemy 对象
from flask import Flask
from flask_sqlalchemy import sqlAlchemy
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
app.config['sqlALCHEMY_TRACK_MODIFICATIONS'] = False
db = sqlAlchemy(app)
最后,在第 13 行,创建 sqlAlchemy 对象 db。
4.3 建立类与表之间的映射
class Student(db.Model):
__tablename__ = 'students'
sno = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String())
age = db.Column(db.Integer)
建立表和类的映射关系:在第 1 行,创建类 Student 继承于 db.Model,表示类 Student 用于映射数据库中的表;在第 2 行,设定 __tablename__ 为 students,表示将类 Student 映射到数据库中的表 students。
建立属性和字段的映射关系:在第 3 行,映射 sno 到表 students 的字段 sno,类型为整数 (db.Integer),primary_key=True 表示该字段是主键;在第 4 行,映射 name 到表 students 的字段 name,类型为整数 (db.String); 在第 5 行,映射 age 到表 students 的字段 age,类型为整数 (db.Integer)。
4.4 使用面向对象的语法访问数据库
students = Student.query.all()
for student in students:
print(student.sno, student.name, student.age)
在第 1 行,类 Student.query.all () 返回所有的学生,相当于使用 sql 语句 “SELECT * from students” 查询所有的学生;在第 3 行,通过 student.sno、student.name
、student.age 即可访问数据库中一条记录的相关字段。
程序运行输出如下:
1 tom 11
2 jerry 12
3 mike 13
4. 源代码下载
5. 小结
本节介绍 ORM 模型的相关概念,使用思维导图概括如下: