1. 级联操作

Cascade意为“级联操作”,就是在操作一个对象的同时,对相关的对象也执行某些操作。我们通过一个Post模型和Comment模型来演示级联操作,分别表示文章(帖子)和评论,两者为一对多关系:

class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(50), unique=True)
body = db.Column(db.Text)
comments = db.relationship('Comment', back_populates='post') class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.Text)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
post = db.relationship('Post', back_populates='comments')

级联行为通过关系函数relationship()的cascade参数设置。我们希望在操作Post对象时,处于附属地位的Comment对象也被相应执行某些操作,这时应该在Post类的关系函数中定义级联参数。设置了cascade参数的一侧将被视为父对象,相关的对象则被视为子对象。

cascade通常使用多个组合值,级联值之间使用逗号分隔,比如:

class Post(db.Model):
...
comments = relationship('Comment', cascade='save-update, merge, delete')

常用的配置组合如下所示:

  • save-update、merge(默认值)
  • save-update、merge、delete
  • all
  • all、delete-orphan

当没有设置cascade参数时,会使用默认值save-update、merge。上面的all等同于除了delete-orphan以外所有可用值的组合,即save-update、merge、refresh-expire、expunge、delete。

下面我们会介绍常用的几个级联值:

  1. save-update

save-update是默认的级联行为,当cascade参数设为save-update时, 如果使用db.session.add()方法将Post对象添加到数据库会话时,那么与Post相关联的Comment对象也将被添加到数据库会话。

我们首先创建一个Post对象和两个Comment对象:

>>> post1 = Post()
>>> comment1 =Comment()
>>> comment2 =Comment()
>>> post1.comments.append(comment1)
>>> post1.comments.append(comment2)

当调用db.session.commit()提交数据库会话时,这三个对象都会被提交到数据库中。

  1. delete

如果某个Post对象被删除,那么按照默认的行为,该Post对象相关联的所有Comment对象都将与这个Post对象取消关联,外键字段的值会被清空。如果Post类的关系函数中cascade参数设为delete时,这些相关的Comment会在关联的Post对象删除时被一并删除。当需要设置delete级联时,我们会将级联值设为all或save-update、merge、delete,比如:

class Post(db.Model):
...
comments = relationship('Comment', cascade='all')
  1. delete-orphan

这个模式是基于delete级联的,必须和delete级联一起使用,通常会设为all、delete-orphan,因为all包含delete。因此当cascade参数设为delete-orphan时,它首先包含delete级联的行为:当某个Post对象被删除时,所有相关的Comment对象都将被删除(delete级联)。除此之外, 当某个Post对象(父对象)与某个Comment对象(子对象)解除关系 时,也会删除该Comment对象,这个解除关系的对象被称为孤立对象(orphan object)。现在comments属性中的级联值为all、delete-orphan,如下所示:

class Post(db.Model):
...
comments = relationship('Comment', cascade='all, delete-orphan')

下面我们将comment5和comment6与post3解除关系并提交数据库会话:

>>> post3.comments.remove(comment5)
>>> post3.comments.remove(comment6)
>>> db.session.commit()

默认情况下,相关评论对象的外键会被设为空值。因为我们设置了 delete-orphan级联,所以现在你会发现解除关系的两条评论记录都被删除了。

delete和delete-orphan通常会在一对多关系模式中,而且“多”这一侧的对象附属于“一”这一侧的对象时使用。尤其是如果“一”这一侧的“父”对象不存在了,那么“多”这一侧的“子”对象不再有意义的情况。比如,文章和评论的关系就是一个典型的示例。当文章被删除了,那么评论也就没必要再留存。在这种情况下,如果不使用级联操作,那么我们就需要手动迭代关系另一侧的所有评论对象,然后一一进行删除操 作。

2.  事件监听

在Flask中,我们可以使用Flask提供的多个装饰器注册请求回调函数,它们会在特定的请求处理环节被执行。类似的,SQLAlchemy也提供了一个listen_for()装饰器,它可以用来注册事件回调函数。

listen_for()装饰器主要接收两个参数,target表示监听的对象,这个对象可以是模型类、类实例或类属性等。identifier参数表示被监听事件的标识符,比如,用于监听属性的事件标识符有set、append、remove、init_scalar、init_collection等。

为了演示事件监听,我们创建了一个Draft模型类表示草稿,其中包含body字段和edit_time字段,分别存储草稿正文和被修改的次数,其中edit_time字段的默认值为0,如下所示:

class Draft(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.Text)
edit_time = db.Column(db.Integer, default=0)

通过注册事件监听函数,我们可以实现在body列修改时,自动叠加表示被修改次数的edit_time字段。在SQLAlchemy中,每个事件都会有一个对应的事件方法,不同的事件方法支持不同的参数。被注册的监听函数需要接收对应事件方法的所有参数,所以具体的监听函数用法因使用的事件而异。设置某个字段值将触发set事件,代码清单5

@db.event.listens_for(Draft.body, 'set')
def increment_edit_time(target, value, oldvalue, initiator):
if target.edit_time is not None:
target.edit_time += 1

我们在listen_for()装饰器中分别传入Draft.body和set作为targe和identifier参数的值。监听函数接收所有set()事件方法接收的参数,其中的target参数表示触发事件的模型类实例,使用target.edit_time即可获取我们需要叠加的字段。其他的参数也需要照常写出,虽然这里没有用到。value表示被设置的值,oldvalue表示被取代的旧值。

当set事件发生在目标对象Draft.body上时,这个监听函数就会被执行,从而自动叠加Draft.edit_time列的值,如下所示:

>>> draft = Draft(body='init')
>>> db.session.add(draft)
>>> db.session.commit()
>>> draft.edit_time 0
>>> draft.body = 'edited'
>>> draft.edit_time 1
>>> draft.body = 'edited again'
>>> draft.edit_time 2
>>> draft.body = 'edited again again'
>>> draft.edit_time 3
>>> db.session.commit()

除了这种传统的参数接收方式,即接收所有事件方法接收的参数,还有一种更简单的方法。通过在listen_for()装饰器中将关键字参数name设为True,可以在监听函数中接收**kwargs作为参数(可变长关键字参数),即“named argument”。然后在函数中可以使用参数名作为键来从**kwargs字典获取对应的参数值:

@db.event.listens_for(Draft.body, 'set', named=True)
def increment_edit_time(**kwargs):
if kwargs['target'].edit_time is not None:
kwargs['target'].edit_time += 1

flask-数据库 进阶的更多相关文章

  1. 【Python全栈-后端开发】数据库进阶

    数据库进阶 python关于mysql的API---pymysql模块 pymsql是Python中操作MySQL的模块,其使用方法和py2的MySQLdb几乎相同. 模块安装 pip install ...

  2. 实验3、Flask数据库操作-如何使用Flask与数据库

    1. 实验内容 数据库的使用对于可交互的Web应用程序是极其重要的,本节我们主要学习如何与各种主要数据库进行连接和使用,以及ORM的使用 2. 实验要点 掌握Flask对于各种主要数据库的连接方法 掌 ...

  3. flask 电子邮件进阶实践-用模板发送163邮件

    电子邮件进阶实践 下面来学习构建邮件的HTML正文,并使用模板组织内容. 一封电子邮件的正文可以是纯文本(text/plain),也可以是HTML格式的文本(text/html).处于全面的考虑,一封 ...

  4. 细说flask数据库迁移

    什么情况下要用数据库迁移? 在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库.最直接的方式就是删除旧表,但这样会丢失数据. 更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化 ...

  5. flask数据库迁移理解及命令

    前言: 使用数据库迁移,可以直接建表,而不用我们自己写sql语句用来建表.就是将关系型数据库的一张张表转化成了Python的一个个类. 在开发中经常会遇到需要修改原来的数据库模型,修改之后更新数据库, ...

  6. 03 flask数据库操作、flask-session、蓝图

    ORM ORM 全拼Object-Relation Mapping,中文意为 对象-关系映射.主要实现模型对象到关系数据库数据的映射. 1.优点 : 只需要面向对象编程, 不需要面向数据库编写代码. ...

  7. flask~数据库

    flask与数据库的连接基于flaks_sqlaichemy 扩展 首先要连接数据库的时候必须得先下载 pip install flask-sqlalchemy 这个扩展 flask框架与数据库的连接 ...

  8. flask数据库操作

    Python 数据库框架 大多数的数据库引擎都有对应的 Python 包,包括开源包和商业包.Flask 并不限制你使用何种类型的数据库包,因此可以根据自己的喜好选择使用 MySQL.Postgres ...

  9. Flask数据库

    一 数据库的设置 Web应用中普遍使用的是关系模型的数据库,关系型数据库把所有的数据都存储在表中,表用来给应用的实体建模,表的列数是固定的,行数是可变的.它使用结构化的查询语言.关系型数据库的列定义了 ...

  10. Flask 数据库迁移

    在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库.最直接的方式就是删除旧表,但这样会丢失数据. 更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中. ...

随机推荐

  1. 谷歌浏览器禁用JS步骤

    前奏: 当你想访问一个页面,因为不符合访问条件,而被JS阻拦:或者你打开的页面特效太多,干扰视线:亦或者JS的某个功能禁止了你的某些行为: 是不是很难受, 好办,咱给他禁了不就好啦,大胆地屏蔽它,不管 ...

  2. 基于光线追踪的渲染中景深(Depth of field)效果的实现

    图形学离线渲染中常用的透视摄像机模型时根据小孔成像的原理建立的,其实现通常是从向成像平面上发射ray,并把trace这条ray的结果作为成像平面上对应交点的采样结果.即: 图片来自<Fundam ...

  3. 【Spring Cloud】 总结

    一.Spring Cloud简介 简单来说,Spring Cloud 就是致力于分布式系统.微服务等的一套在目前非常火热的框架.但它的本身也是一系列框架的有序集合(由多个模块组成). 相比较于Dubb ...

  4. axiso基本使用及python接收处理

    安装$ npm install axios 1.发送get请求: axios.get("/api/v1.0/cars?id=132").then(function(res){ co ...

  5. 3.java并发包

    1.java并发包介绍 JDK5.0 以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent 包中,是专门用于多线程并发编程的,充分利用了现代多处理器 和多核心系统的功 ...

  6. PAT Basic 1021 个位数统计 (15 分)

    给定一个 k 位整数 1 (0, ,, d​k−1​​>0),请编写程序统计每种不同的个位数字出现的次数.例如:给定 0,则有 2 个 0,3 个 1,和 1 个 3. 输入格式: 每个输入包含 ...

  7. mongo批量插入问题(insert_many,bulk_write),spark df转json传入mongo

    https://blog.csdn.net/nihaoxiaocui/article/details/95060906 https://xuexiyuan.cn/article/detail/173. ...

  8. 数据库——Oracle(4)

    1 Oracle中常用字符处理函数:用来处理char,varchar以及varchar2类型数据. 1)length(列名/字符串):统计当前该列的列值/字符串中字符的个数 select ename, ...

  9. Java通过腾讯邮箱发送邮件

    private static void sendEmaill() { Properties prop = new Properties(); //协议 prop.setProperty("m ...

  10. 报表开发工具!DevExpress Reporting v19.1:WPF/Web平台报表

    行业领先的.NET界面控件DevExpress Reporting全新发布了v19.1版本,本文主要为大家介绍WPF.Web平台中DevExpress Reporting发布的一些新功能及增强部分功能 ...