
4.4 使用Flask-SQLAlchemy操作数据库

完成数据库关系图的配置工作后,接下来就可以随时使用这个数据库了。在本节的内容中,将详细介绍在Python shell中使用Flask-SQLAlchemy操作数据库的知识。
4.4.1 新建表
在Flask-SQLAlchemy中,可以通过方法db.create_all()根据模型类创建数据库。

如果此时查看程序目录,会发现新建了一个名为data.sqlite的数据库文件。这是一个SQLite数据库文件,数据库名字是在Flask配置文件或配置变量中指定的。如果在数据库data.sqlite中已经存在了数据库表,那么方法db.create_all()不会重新创建或者更新这个表。但是如果希望在修改模型后把改动内容更新到现有的数据库中,方法db.create_all()的这一特性会带来很大的弊端。此时可以考虑另一种解决方案,例如如下所示的先删除旧表再重新创建新表的方法,但是这样会销毁数据库中原有的数据。

4.4.2 添加行
在使用Flask-SQLAlchemy扩展时,可以通过如下命令创建新的角色和用户。

通过上述代码添加了3个用户aaa、bbb和ccc,其中aaa是管理员。在创建过程中没有明确设定这些新建对象的id属性,此时这些对象只是存在Python中,还没有被写入到数据库中,所以现在还没有给新建的用户id赋值,例如使用print打印rank.id值时会显示None。

接下来可以使用数据库会话管理对数据库所做的改动,在Flask-SQLAlchemy中使用db.session表示会话。再将上面新创建的用户写入数据库之前,需要先将对象实例添加到会话中。

接下来使用方法commit()提交会话。

此时已经把新建的用户对象写入数据库中,如果这时再次打印输出rank.id的值,会发现现在它们已经被赋值了。

注意:数据库会话的好处是能保证数据库的一致性,提交操作使用原子方式把会话中的对象全部写入数据库。如果在写入会话的过程中发生错误,那么整个会话都会失效。如果始终把相关改动放在会话中提交,就可以避免因部分更新导致的数据库不一致性。
4.4.3 修改行
在使用Flask-SQLAlchemy扩展时,可以修改某个对象的模型,可以通过在数据库会话中调用add()实现。接下来继续在之前的shell命令行界面中进行操作,例如在下面的例子中,把Admin角色重命名为Admin123。

4.4.4 删除行
在使用Flask-SQLAlchemy扩展时,可以使用方法delete()删除数据库中名为Moderator的角色。

注意:删除与插入和更新一样,提交数据库会话后才会执行。
4.4.5 查询行
在使用Flask-SQLAlchemy扩展时,可以使用模型类的query对象查询数据库中的数据,例如下面的代码可以分别获取对应表Rank和User中的所有数据。

在query对象中可以使用配置过滤器实现更精确的数据库查询,例如在下面的代码中,查找了数据库中所有角色为User的用户。

通过下面的演示代码,可以生成SQLAlchemy查询的原生SQL查询语句。

通过下面的演示代码,加载一个名为User的用户角色。

在query对象中使用filter_by()等过滤器方法,可以查询到一个更精确的query对象。在Flask Web程序中,可以一次性调用多个过滤器实现复杂的查询功能。具体来说,在Flask-SQLAlchemy的query对象中可以调用如下所示的过滤器。
• filter():把过滤器添加到原始查询上,返回一个新的查询。
• filter_by():把指定值的过滤器添加到原始查询上,返回一个新的查询。
• limit():使用指定的值来限制原始查询返回的结果数量,返回一个新的查询。
• offset():偏移原始查询返回的结果,返回一个新的查询。
• order_by():根据指定条件对原始查询结果进行排序,返回一个新的查询。
• group_by():根据指定条件对原始查询的结果进行分组,返回一个新的查询。
在Flask-SQLAlchemy的查询语句中使用过滤器后,可以调用方法all()查询并显示能够以列表的形式返回的结果。在Flask-SQLAlchemy中,除了可以使用方法all()外,还可以在查询操作中使用如下所示的方法。
• all():以列表的形式返回所有的查询结果。
• first():返回查询结果中的第一个值,如果没有查询结果则返回None。
• first_or_404():返回查询结果中的第一个值,如果没有查询结果则终止请求,并返回404错误指示。
• get():返回指定主键对应的行信息,如果没有对应的行则返回None。
• get_or_404():返回指定主键对应的行信息,如果没有对应的行则终止请求,并返回404错误提示。
• count():返回查询结果的数量。
• paginate():返回一个Paginate对象,它包含指定范围内的结果。
例如在下面的例子中,分别从关系的两端查询角色和用户之间的一对多关系。


在上述代码中执行user_rank.users表达式时,隐式查询会调用all()方法返回一个用户列表。因为query对象是隐式查询,所以无法设置更精确的查询过滤器。针对上述演示过程,可以修改关系中的设置参数,例如在如下所示的代码中添加新的设置参数lazy='dynamic',这样可以禁止自动执行查询功能。

这样在配置关系之后,user_rank.users会返回一个尚未执行的查询,因此可以在上面添加过滤器,代码如下所示。

4.4.6 在视图函数中操作数据库
在使用Flask-SQLAlchemy扩展时,可以在视图函数中使用本章前面介绍的数据库操作方法。例如在下面的实例中,展示了实现首页路由功能的方法,能够把在表单中输入的username写入数据库中。

在用户输入名字并提交表单后,会使用方法filter_by()在数据库中过滤查询提交的名字。使用session将变量known写入用户会话中,在URL重定向后可以把数据传给模板,用于显示自定义的欢迎消息。读者需要注意,要想正常运行上述程序,必须在Python命令行中创建数据库表。例如下面是上述视图代码对应的模板文件实现,使用参数known在欢迎消息中加入了第二行,从而可以对已知用户和新用户显示不同的内容。


4.4.7 使用Flask-SQLAlchemy实现一个简易登录系统
在下面的实例中,演示了使用Flask-SQLAlchemy扩展库实现一个简易登录系统的过程。
源码路径:daima\4\4-4\sql\
1)首先看程序文件hello.py,具体实现流程如下所示。
① 配置数据库,其中对象db是Flask-SQLAlchemy类的实例,表示程序使用的数据库,同时还获得了Flask-SQLAlchemy提供的所有功能,具体代码如下所示。

② 定义Rank和User模型,Flask-SQLAlchemy创建的数据库实例为模型提供了一个基类以及一系列辅助类和辅助函数,可用于定义模型的结构。本实例中的数据库表Ranks和users可以分别定义为模型Rank和User,具体代码如下所示。

2)模板文件index.html非常简单,能够获取用户的登录信息并显示账户信息,具体实现代码如下所示。

在浏览器中输入“http://127.0.0.1:5000/”后的执行效果如图4-6所示。在表单中随便输入一个名字,例如输入“aaa”并单击“提交”按钮后,会在表单上面显示对用户“aaa”的欢迎信息,如图4-7所示。

图4-6 初始执行效果
如果在表单中输入另外一个名字,例如输入“bbb”,单击“提交”按钮后会显示对用户“bbb”的欢迎信息。并在上方显示“看来你改了名字!”的文本提示,如图4-8所示。

图4-7 显示对用户“aaa”的欢迎信息

图4-8 修改名字时的提示信息
4.4.8 使用Flask-SQLAlchemy实现小型BBS系统
在下面的实例中,演示了使用Flask-SQLAlchemy扩展库实现BBS系统的过程。本实例不但实现了会员注册和登录验证功能,而且还实现了发布BBS信息功能。
源码路径:daima\4\4-4\myBlog\
1)首先看程序文件123.py,使用Flask-SQLAlchemy根据类的代码创建数据库表,主要实现代码如下所示。


执行后会在数据库bloguser中分别创建表Category和User,并在表中分别创建对应的字段。
2)在文件blog_message.py中实现URL路径导航功能,每个页面的具体说明如下所示。
① 链接“/”实现系统主页视图,查询数据库内的所有categorys信息并显示出来,具体的实现代码如下所示。

② 链接“/add_entry”实现发布BBS信息功能视图,能够向数据库中添加新的BBS信息,具体的实现代码如下所示。

③ 链接“/login”实现用户登录表单视图,获取表单中的用户名和密码,然后验证在数据库中是否存在,具体的实现代码如下所示。


④ 链接“/go2regist”跳转到用户注册界面的模板文件regist.html,具体的实现代码如下所示。

⑤ 链接“/regist”跳转到用户注册验证界面视图,验证用户输入的注册数据是否合法,如果合法则将注册信息添加到数据库中,具体的实现代码如下所示。

⑥ 链接“/logout”实现用户注销功能,具体的实现代码如下所示。

在浏览器中输入“http://127.0.0.1:8000/”来到系统主页,如图4-9所示。
用户登录界面如图4-10所示,用户注册界面如图4-11所示。

图4-9 系统主页

图4-10 用户登录界面

图4-11 用户注册界面