有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

时间:2024-03-14 14:06:30

又是新的工作日,老项和小王也是早早来到了公司,准备好电脑,查看了一下小王完成的前一天的任务,老项也开始了自己的讲课时间。

老项说:“今天我们就讲解flask下数据库相关操作,今天讲完以后,你就可以设计数据库模型,然后把项目的数据库部分做起来了。”

小王调皮的说:“来吧,老铁,开始传功吧!我的大脑已经急不可耐!”

 

数据库三方包的安装和配置

我们知道flask的核心并不包含对数据库的处理,要使用数据库,需要使用第三方包,这里我们选用flask-sqlalchemy,使用flask-sqlalchemy可以实现数据库的orm(Object-Relational Mapping即对象关系映射)操作,可以让我们使用面向对象的方式操作数据库。但是sqlalchemy并不包含数据库引擎,小王的项目需要使用mysql数据库,因此,我们还需要安装mysql的数据库引擎,这里我们选用flask-mysqldb。在虚拟环境下安装截图如下。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

 

安装好两个第三方包后,需要去配置一下数据库。我们暂时把配置代码放在app.py里面。代码如下图。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

 

主要看第六行对数据库配置的代码。我们来看这行代码右边的字符串,第一个mysql是指的数据库类型,这里的数据库类型可以是mysql,oracle,postgres,sqlite。后面的root是指的数据库的用户名,root后面的bb12345表示数据库密码(哎呀,一不小心把本机的数据库密码泄露了,讲到这里,老项暗想)。@后面是连接的服务器地址,这里指本地ip,ip后面的3306是数据库的端口,最后的car_db是本地构建的数据库名称。在使用数据库前,要先安装mysql数据库(安装过程可以参考我们mysql安装的教程,这里不再赘述),然后提前构建好数据库。可以使用navicat构建数据库,也可以使用数据库的指令创建数据库,注意编码方式选择UTF-8,见下图。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

除了以上配置外,还有一些有用的配置,如下图。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

关于更多的配置和更详细的信息请参考下表。

配置名称

配置意义

SQLALCHEMY_DATABASE_URI

连接数据库的URI配置,具体的配置方法请参考上面的说明

SQLALCHEMY_BINDS

一个字典,该字典通过绑定的key连接URI

SQLALCHEMY_ECHO

主要用于debug,为True的时候会回显数据库操作的原语

SQLALCHEMY_RECORD_QUERIES

用于禁用或者启用查询记录。查询记录在调试或者测试模式会自动启用。

SQLALCHEMY_NATIVE_UNICODE

用于禁用原生的unicode支持。

SQLALCHEMY_POOL_SIZE

数据库连接池的大小,默认为5

SQLALCHEMY_POOL_TIMEOUT

指定数据库连接池的连接超时时间

SQLALCHEMY_POOL_RECYCLE

指定多久以后自动回收数据库

关于配置就先说这么多,下面我们来说一下flask-sqlalchemy中数据库的常用字段和一些选项。

 

sqlalchemy常用字段,选项

我们知道数据库里面的数据是有不同类型的。而sqlalchemy要对数据库进行映射,也需要对数据库的数据类型进行映射。映射后,sqlalchemy的主要字段类型可以参考下表。

 

字段类型名

对应的Python类型

字段说明

Integer

int

普通整数,一般是 32 位

SmallInteger

int

取值范围小的整数,一般是 16 位

Big Integer

int 或 long

不限制精度的整数

Float

float

浮点数

Numeric

decimal.Decimal

定点数

String

str

变长字符串

Text

str

变长字符串,对较长或不限长度的字符串做了优化

Unicode

unicode

变长 Unicode 字符串

Unicode Text

unicode

变长 Unicode 字符串,对较长或不限长度的字符串做了优化

Boolean

bool

布尔值

Date

datetime.date

日期

Time

datetime.time

时间

DateTime

datetime.datetime

日期和时间

Interval

datetime.timedelta

时间间隔

Enum

str

一组字符串

PickleType

任何 Python 对象

自动使用 Pickle 序列化

LargeBinary

str

二进制文件

我们在定义数据模型的时候,就需要根据模型的不同字段的意义给字段匹配不同的类型。比如类似于数量的字段,就需要整型,类似于名称,说明或者内容的字段就需要字符型。

对于不同的字段,可能还会有一些选项,比如该字段是否是主键,该字段的值是否允许重复,这些选项也被称为列选项。sqlalchemy的常见列选项见下表。

选项名称

选项说明

primary_key

如果设为 True,该列就是表的主键,注意:每个模型都应该有一个主键。一般会专门用一个名为id的字段来定义主键

unique

如果设为 True,该列不允许出现重复的值

index

如果设为 True,为该列创建索引,提升查询效率

nullable

如果设为 True,该列允许使用空值;如果设为 False,这列不允许使用空值

default

为该列定义默认值

下面我们就以小王的项目为例,来构建一个数据模型。对于不同品牌的车,我们可以设计如下表这个简单的数据模型。

字段名称

字段意义

id

主键

name

品牌的名称 如 长安  宝马 名字不能重复

content

品牌介绍 可以为空

         按照上面的数据模型,在flask中构建数据模型代码如下。

         有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

         根据上图,定义数据模型的步骤如下:

  1. 导入SQLAlchemy,代码第二行
  2. 第7行和第9行用于配置数据库,你也可以把配置封装到一个类里面,如下图

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

  1. 实例化一个数据库对象,代码第十行
  2. 以db.Model为父类,构建数据模型类,代码13---20行
  3. 数据模型中的字段均是db.Colum类的实例,实例化传参的时候指定字段类型和选项,见代码15---17行
  4. 最后,重载了魔法方法__repr__,这个魔法方法只是为了在调试或者测试的时候,让模型对象有更好的可读性,不是必须实现的。

 

“老项,我记得数据库里面表和表之间还有关系,比如一对多,这种关系在sqlalchemy该如何表达呢?”老项刚讲完数据模型的定义,小王又开始提问了。

“这个就是我马上要说的,就是如何在sqlalchemy中表达不同的数据表关系”老项回答完,又开始继续后面的讲解。

 

sqlalchemy表关系

在sqlalchemy中,用一些选项来表达表和表之间的一些关系。选项关系如下表所示。

选项名称

选项说明

backref

在关系的另一个模型中添加反向引用

primaryjoin

明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定.

lazy

 

 

 

 

 

 

指定如何加载相关记录。可选值如下 :

select(首次访问时按需加载)

immediate(源对象加载后就加载)

joined(加载记录,但使用联结)

subquery(立即加载,但使用子查询)

noload(永不加载)

dynamic(不加载记录,但提供加载记录的查询)

uselist

如果设为 Fales,不使用列表,而使用标量值

order_by

指定关系中记录的排序方式

secondary

指定多对多关系中关系表的名字

secondaryjoin

SQLAlchemy 无法自行决定时,指定多对多关系中的二级联结条件

还是以小王的项目为例,不同的汽车品牌下,还有不同的车系,比如比亚迪品牌下,还有秦,宋,元等不同车系,所以我们还需要一个车系表。而品牌表和车系表就是一种一对多的关系,一个品牌下可以有多种车系,而某一个车系只能对应一种品牌。我们车系表设计如下。

字段名称

字段说明

id

车系id

name

车系名称 不可重复

content

车系说明 可以为空

status

车系状态 停售或者在售

根据数据模型的设计要求以及外键关系,我们的代码如下图。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

注意代码的27行,是backref的固定写法,表示反向引用,这个relationship方法的第一个参数表关联那个模型类,这里关联的是CarSerial类,第二个参数表示新增的属性,名字可以任意取。我们再看代码的39行,该行代码定义了一个外键的id,注意这个id应该在一对多中,多的一方定义,定义的时候第二个参数使用了db.ForeignKey来确定外键关系,里面的参数就是一对多中,一那一方的id。

我们的数据模型建立好以后,就可以对数据库进行操作了。

 

数据库的orm操作

创建并增加数据

我们暂时把数据库的操作放在index的视图里面。创建表和插入数据的操作请参考如下图代码。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

    上图代码中,创建表并增加数据的操作步骤如下:

  1. 使用create_all()方法创建表,第47行代码
  2. 实例化模型对象,第48行代码,注意这里不需要传递id这个参数
  3. 使用会话session添加数据行,第49行代码
  4. 使用会话进行提交处理,第50行。注意提交以后,数据才能生效
  5. 如果有一对多关系,应该先提交一的一方,提交后,在对多的一方进行操作,包括实例化模型对象,添加数据化和提交等操作。52---55行。
  6. 也可以使用add_all()方法,同时添加多个数据行,第54行代码。

我们访问http://127.0.0.1:5000/index,然后到数据库工具进行查询,可以看到如下结果。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

查询数据

我们创建了表,并添加了一些数据。下面我们查询一下数据,并把数据通过视图方法展示到页面上。前后台代码如下。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

在后端代码中,47行使用all()方法查询品牌表中的所有数据,48行使用get方法查询id为1的数据,注意参数是id,49行使用会话的方式配合filter查询id为1这个品牌下的所有车系。50行直接使用对象的query.filter进行过滤查询。注意过滤条件写“==”。然后按照模板讲的方法对数据进行传递,在前端页面渲染数据。就可以在页面*问到数据库的数据了。filter支持下表更多的过滤操作。

操作案例(只写出filter方法里面的内容)

意义(请运行代码,自行将意义填写在表中)

CarSerial.name==‘宝马’

 

CarSerial.name!=‘宝马’

 

CarSerial.name.like(‘bwm’)

 

CarSerial.name.in_(['奔驰', '宝马'])

 

~CarSerial.name.in_(['奔驰', '宝马'])

 

CarSerial.name == None

 

CarSerial.name != None

 

from sqlalchemy import and_
and_( CarSerial.name == '宝马', CarSerial.content == '华晨宝马')

 

from sqlalchemy import or_
or_( CarSerial.name == '宝马', CarSerial.content == '华晨宝马')

 

 

 

删除数据

在flask中,要删除某一条数据也比较简单,代码见下图。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

在代码中,删除一条数据前,首先要查询到需要删除的数据(47行代码),然后使用会话的方式执行删除动作并提交(48-49行代码)。操作后的数据库变化如下图所示。

运行前

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

运行后

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

 

修改数据

如果要修改某一条数据,也需要先查询到该数据,然后进行修改,代码如下图。

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

 

代码中,修改的主要操作是第48和49行代码,注意修改后也需要提交。修改后数据库的变化如下图。

运行前

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

运行后

有故事,带项目的flask教程(5)---flask的数据库模型和orm操作

“好了,小王,关于在flask中使用sqlalchemy操作数据库的基本方法就先给你说这么多。今天有空一定要把讲的操作都好好练习一遍,你也可以开始设计数据库,实现数据模型了。”老项讲完,给小王布置了新的任务。

 

“遵命,老项,保证完成任务。”小王嘿嘿一笑,回答道。

 

本章任务:

  1. 在虚拟环境中,安装教程中的两个包
  2. 配置安装好mysql数据库
  3. 对教程中的所有案例和任务进行练习
  4. 根据小王项目的需求,结合汽车品牌,车系,车型等汽车的实际信息,设计数据库
  5. 实现对应数据库的数据模型