赵走x博客
网站访问量:151444
首页
书籍
软件
工具
古诗词
搜索
登录
Flask 实战:41、电子邮件进阶实践
Flask 实战:40、使用事务邮件服务SendGird
Flask 实战:39、使用Flask-Mail发送电子邮件
Flask 实战:38、数据库进阶实践
Flask 实战:37、更新数据库表
Flask 实战:36、定义关系
Flask 实战:35、在视图函数里操作数据库
Flask 实战:34、数据库操作:CRUD
Flask 实战:33、使用Flask-SQLAlchemy管理数据库
Flask 实战:32、ORM魔法
Flask 实战:31、数据库的分类
Flask 实战:30、单个页面多个表单
Flask 实战:29、单个表单多个提交按钮
Flask 实战:28、使用Flask-CKEditor集成富文本编辑器
Flask 实战:27、多文件上传
Flask 实战:26、文件上传
Flask 实战:25、自定义验证器
Flask 实战:24、使用宏渲染表单
Flask 实战:23、设置错误消息语言
Flask 实战:22、处理表单数据
Flask 实战:21、使用Flask-WTF处理表单
Flask 实战:20、HTML表单
Flask 实战:19、模板进阶实践
Flask 实战:18、模板结构组织
Flask 实战:17、模板辅助工具
Flask 实战:16、模板基本用法
Flask 实战:15、HTTP进阶实践
Flask 实战:14、Flask上下文
Flask 实战:13、HTTP响应
Flask 实战:12、HTTP请求
Flask 实战:11、请求响应循环
Flask 实战:10、Flask与MVC架构
Flask 实战:9、模板与静态文件
Flask 实战:8、Flask命令
Flask 实战:7、URL与端点
Flask 实战:6、项目配置
Flask 实战:5、Flask扩展
Flask 实战:4、Python Shell
Flask 实战:3、启动开发服务器
Flask 实战:2、Hello,Flask!
Flask 实战:1、初识Flask
Flask 实战:34、数据库操作:CRUD
资源编号:75885
Python Web
Flask Web开发实战:入门、进阶与原理解析
热度:94
现在我们创建了模型,也生成了数据库和表,是时候来学习常用的数据库操作了。数据库操作主要是CRUD,即Create(创建)、Read(读取/查询)、Update(更新)和Delete(删除)。
现在我们创建了模型,也生成了数据库和表,是时候来学习常用的数据库操作了。数据库操作主要是CRUD,即Create(创建)、Read(读取/查询)、Update(更新)和Delete(删除)。 SQLAlchemy使用数据库会话来管理数据库操作,这里的数据库会话也称为事务(transaction)。Flask-SQLAlchemy自动帮我们创建会话,可以通过db.session属性获取。 >注意 SQLAlchemy中的数据库会话对象和我们在前面介绍的Flask中的session无关。 数据库中的会话代表一个临时存储区,你对数据库做出的改动都会存放在这里。你可以调用add()方法将新创建的对象添加到数据库会话中,或是对会话中的对象进行更新。只有当你对数据库会话对象调用commit()方法时,改动才被提交到数据库,这确保了数据提交的一致性。另外,数据库会话也支持回滚操作。当你对会话调用rollback()方法时,添加到会话中且未提交的改动都将被撤销。 这一节我们会在Python Shell中演示CRUD操作。默认情况下,Flask-SQLAlchemy(>=2.3.0版本)会自动为模型类生成一个__repr__()方法。当在Python Shell中调用模型的对象时,__repr__()方法会返回一条类似“<模型类名主键值>”的字符串,比如
。为了便于实际操作测试,示例程序中,所有的模型类都重新定义了__repr__()方法,返回一些更有用的信息,比如: ``` class Note(db.Model): ... def __repr__(self): return '
' % self.body ``` 在实际开发中,这并不是必须的。另外,为了节省篇幅,后面的模型类定义不会给出这部分代码,具体可到源码仓库中查看。 # 1.Create 添加一条新记录到数据库主要分为三步: * 1)创建Python对象(实例化模型类)作为一条记录。 * 2)添加新创建的记录到数据库会话。 * 3)提交数据库会话。 下面的示例向数据库中添加了三条留言: ``` >>> from app import db, Note >>> note1 = Note(body='remember Sammy Jankis') >>> note2 = Note(body='SHAVE') >>> note3 = Note(body='DON'T BELIEVE HIS LIES, HE IS THE ONE, KILL HIM') >>> db.session.add(note1) >>> db.session.add(note2) >>> db.session.add(note3) >>> db.session.commit() ``` 在这个示例中,我们首先从app模块导入db对象和Note类,然后分别创建三个Note实例表示三条记录,使用关键字参数传入字段数据。我们的Note类继承自db.Model基类,db.Model基类会为Note类提供一个构造函数,接收匹配类属性名称的参数值,并赋值给对应的类属性,所以我们不需要自己在Note类中定义构造方法。接着我们调用add()方法把这三个Note对象添加到会话对象db.session中,最后调用commit()方法提交会话。 > 提示 除了依次调用add()方法添加多个记录,也可以使用add_all()一次添加包含所有记录对象的列表。 你可能注意到了,我们在创建模型类实例的时候并没有定义id字段的数据,这是因为主键由SQLAlchemy管理。模型类对象创建后作为临时对象(transient),当你提交数据库会话后,模型类对象才会转换为数据库记录写入数据库中,这时模型类对象会自动获得id值: ``` >>> note1.id 1 ``` >注意 Flask-SQLAlchemy提供了一个SQLALCHEMY_COMMIT_ON_TEARDOWN配置变量,将其设为True可以设置自动调用commit()方法提交数据库会话。因为存在潜在的Bug,目前已不建议使用,而且未来版本中将移除该配置变量。请避免使用该配置变量,可使用手动调用db.session.commit()方法的方式提交数据库会话。 # 2.Read 我们已经知道了如何向数据库里添加记录,那么如何从数据库里取回数据呢?使用模型类提供的query属性附加调用各种过滤方法及查询方法可以完成这个任务。 一般来说,一个完整的查询遵循下面的模式: ``` <模型类>.query.<过滤方法>.<查询方法> ``` 从某个模型类出发,通过在query属性对应的Query对象上附加的过滤方法和查询函数对模型类对应的表中的记录进行各种筛选和调整,最终返回包含对应数据库记录数据的模型类实例,对返回的实例调用属性即可获取对应的字段数据。 如果你执行了上面小节里的操作,我们的数据库现在一共会有三条记录,如表5-5所示。  表5-5 note表示意 SQLAlchemy提供了许多查询方法用来获取记录,表5-6列出了常用的查询方法。   表5-6 常用的SQLAlchemy查询方法 >附注 表5-6中的first_or_404()、get_or_404()以及paginate()方法是Flask-SQLAlchemy附加的查询方法。 下面是对Note类进行查询的几个示例。all()返回所有记录: ``` >>> Note.query.all() [
,
,
] ``` first()返回第一条记录: ``` >>> note1 = Note.query.first() >>> note1
>>> note1.body u'remember Sammy Jankis' ``` get()返回指定主键值(id字段)的记录: ``` >>> note2 = Note.query.get(2) >>> note2
``` count()返回记录的数量: ``` >>> Note.query.count() 3 ``` SQLAlchemy还提供了许多过滤方法,使用这些过滤方法可以获取更精确的查询,比如获取指定字段值的记录。对模型类的query属性存储的Query对象调用过滤方法将返回一个更精确的Query对象(后面我们简称为查询对象)。因为每个过滤方法都会返回新的查询对象,所以过滤器可以叠加使用。在查询对象上调用前面介绍的查询方法,即可获得一个包含过滤后的记录的列表。常用的查询过滤方法如表5-7所示。  表5-7 常用的SQLAlchemy过滤方法 > 提示 完整的查询方法和过滤方法列表在[http://docs.sqlalchemy.org/en/latest/orm/query.html](http://docs.sqlalchemy.org/en/latest/orm/query.html) 可以看到。 filter()方法是最基础的查询方法。它使用指定的规则来过滤记录,下面的示例在数据库里找出了body字段值为“SHAVE”的记录: ``` >>> Note.query.filter(Note.body='SHAVE').first()
``` 直接打印查询对象或将其转换为字符串可以查看对应的SQL语句: ``` >>> print(Note.query.filter_by(body='SHAVE')) SELECT note.id AS note_id, note.body AS note_body FROM note WHERE note.body = ? ``` 在filter()方法中传入表达式时,除了“==”以及表示不等于的“!=”,其他常用的查询操作符以及使用示例如下所示: LIKE: ``` filter(Note.body.like('%foo%')) ``` IN: ``` filter(Note.body.in_(['foo', 'bar', 'baz'])) ``` NOT IN: ``` filter(~Note.body.in_(['foo', 'bar', 'baz'])) ``` AND: ``` # 使用and_() from sqlalchemy import and_ filter(and_(Note.body == 'foo', Note.title == 'FooBar')) # 或在filter()中加入多个表达式,使用逗号分隔 filter(Note.body == 'foo', Note.title == 'FooBar') # 或叠加调用多个filter()/filter_by()方法 filter(Note.body == 'foo').filter(Note.title == 'FooBar') ``` OR: ``` from sqlalchemy import or_ filter(or_(Note.body == 'foo', Note.body == 'bar')) ``` > 附注 完整的可用操作符列表可以访问[http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.operators.ColumnOperators](http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.operators.ColumnOperators) 查看。 和filter()方法相比,filter_by()方法更易于使用。在filter_by()方法中,你可以使用关键字表达式来指定过滤规则。更方便的是,你可以在这个过滤器中直接使用字段名称。下面的示例使用filter_by()过滤器完成了同样的任务: ``` >>> Note.query.filter_by(body='SHAVE').first()
``` 其他的查询方法我们会在后面具体应用时详细介绍。 # 3.Update 更新一条记录非常简单,直接赋值给模型类的字段属性就可以改变字段值,然后调用commit()方法提交会话即可。下面的示例改变了一条记录的body字段的值: ``` >>> note = Note.query.get(2) >>> note.body u'SHAVE' >>> note.body = 'SHAVE LEFT THIGH' >>> db.session.commit() ``` 只有要插入新的记录或要将现有的记录添加到会话中时才需要使用add()方法,单纯要更新现有的记录时只需要直接为属性赋新值,然后提交会话。 # 4.Delete 删除记录和添加记录很相似,不过要把add()方法换成delete()方法,最后都需要调用commit()方法提交修改。下面的示例删除了id(主键)为2的记录: ``` >>> note = Note.query.get(2) >>> db.session.delete(note) >>> db.session.commit() ```