Flask开发系列之数据库操作
Python数据库框架
我们可以在Flask中使用MySQL、Postgres、SQLite、Redis、MongoDB 或者 CouchDB。
还有一些数据库抽象层代码包供选择,例如 SQLAlchemy 和MongoEngine。你可以使用这些抽象包直接处理高等级的 Python 对象,而不用处理如表、文档或查询语言此类的数据库实体。
使用Flask-SQLAlchemy管理数据库
我们选择使用的数据库框架是 Flask-SQLAlchemy(http://pythonhosted.org/Flask-SQLAlchemy/),这个 Flask 扩展包装了 SQLAlchemy(http://www.sqlalchemy.org/)框架。
Flask-SQLAlchemy 是一个 Flask 扩展,简化了在 Flask 程序中使用 SQLAlchemy 的操作。
SQLAlchemy 是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy 提供了高层 ORM,也提供了使用数据库原生 SQL 的低层功能。
安装
(venv) $ pip install flask-sqlalchemy
在 Flask-SQLAlchemy怎么使用数据库
在 Flask-SQLAlchemy 中,数据库使用 URL 指定。最流行的数据库引擎采用的数据库 URL。
FLask-SQLAlchemy数据库URL如下所示:
数据库引擎 URL MySQL mysql://username:password@hostname/database Postgres postgresql://username:password@hostname/database SQLite(Unix) sqlite:////absolute/path/to/database SQLite(Windows) sqlite:///c:/absolute/path/to/database
在这些 URL 中,hostname 表示 MySQL 服务所在的主机,可以是本地主机(localhost),
也可以是远程服务器。数据库服务器上可以托管多个数据库,因此 database 表示要使用的
数据库名。如果数据库需要进行认证,username 和 password 表示数据库用户密令。
注意:SQLite 数据库不需要使用服务器,因此不用指定 hostname、username 和password。URL 中的 database 是硬盘上文件的文件名。
配置数据库
程序使用的数据库 URL 必须保存到 Flask 配置对象的 SQLALCHEMY_DATABASE_URI 键中。配置对象中还有一个很有用的选项,即 SQLALCHEMY_COMMIT_ON_TEARDOWN 键,将其设为 True时,每次请求结束后都会自动提交数据库中的变动。其他配置选项的作用请参阅 Flask-SQLAlchemy 的文档。
test.py
from flask_sqlalchemy import SQLAlchemy from flask import Flask import os basedir = os.path.abspath(os.path.dirname(__file__)) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] =\ 'sqlite:///' + os.path.join(basedir, 'data.sqlite') app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app)
db 对象是 SQLAlchemy 类的实例,表示程序使用的数据库,同时还获得了 Flask-SQLAlchemy提供的所有功能。
定义模型
模型这个术语表示程序使用的持久化实体。在 ORM 中,模型一般是一个 Python 类,类中的属性对应数据库表中的列。
test.py:定义 Role 和 User 模型
class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) def __repr__(self): return '' % self.name class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) def __repr__(self): return ' ' % self.username
类变量 __tablename__ 定义在数据库中使用的表名。如果没有定义 __tablename__ ,Flask-SQLAlchemy 会使用一个默认名字,但默认的表名没有遵守使用复数形式进行命名的约定,所以最好由我们自己来指定表名。
其余的类变量是该模型的属性,被定义为 db.Column类的实例。
注意:Flask-SQLAlchemy 要求每个模型都要定义 主键 ,这一列经常命名为 id 。
db.Column 类构造函数的第一个参数是数据库列和模型属性的类型。 最常用的SQLAlchemy列类型 类型名 Python类型 说 明 Integer int 普通整数,一般是 32 位 SmallInteger int 取值范围小的整数,一般是 16 位 BigInteger int 或 long 不限制精度的整数 Float float 浮点数 Numeric decimal.Decimal 定点数 String str 变长字符串 Text str 变长字符串,对较长或不限长度的字符串做了优化 Unicode unicode 变长 Unicode 字符串 UnicodeText unicode 变长 Unicode 字符串,对较长或不限长度的字符串做了优化 Boolean bool 布尔值 Date datetime.date 日期 Time datetime.time 时间 DateTime datetime.datetime 日期和时间 Interval datetime.timedelta 时间间隔 Enum str 一组字符串 PickleType 任何 Python 对象 自动使用 Pickle 序列化 LargeBinary str 二进制文件 db.Column 中其余的参数指定属性的配置选项。列出了一些可用选项。 最常使用的SQLAlchemy列选项 选项名 说 明 primary_key 如果设为 True ,这列就是表的主键 unique 如果设为 True ,这列不允许出现重复的值 index 如果设为 True ,为这列创建索引,提升查询效率 nullable 如果设为 True ,这列允许使用空值;如果设为 False ,这列不允许使用空值 default 为这列定义默认值
数据库操作
创建表
(venv) $ python test.py shell
>>> from hello import db
>>> db.create_all()
如果修改模型后要把改动应用到现有的数据库中,这一特性会带来不便,它把数据库中原有的数据都销毁了。更新现有数据库表的粗暴方式是先删除旧表再重新创建:
>>> db.drop_all()
>>> db.create_all()
插入行
下面这段代码创建了一些角色和用户:
>>> from hello import Role, User
>>> admin_role = Role(name='Admin')
>>> mod_role = Role(name='Moderator')
>>> user_role = Role(name='User')
>>> user_john = User(username='john', role=admin_role)
>>> user_susan = User(username='susan', role=user_role)
>>> user_david = User(username='david', role=user_role)
通过数据库会话管理对数据库所做的改动,在 Flask-SQLAlchemy 中,会话由 db.session表示。准备把对象写入数据库之前,先要将其添加到会话中:
>>> db.session.add(admin_role)
>>> db.session.add(mod_role)
>>> db.session.add(user_role)
>>> db.session.add(user_john)
>>> db.session.add(user_susan)
>>> db.session.add(user_david)
或者简写成:
>>> db.session.add_all([admin_role, mod_role, user_role,
... user_john, user_susan, user_david])
为了把对象写入数据库,我们要调用 commit() 方法提交会话:
>>> db.session.commit()
注意:数据库会话能保证数据库的一致性。提交操作使用原子方式把会话中的对象全部写入数据库。如果在写入会话的过程中发生了错误,整个会话都会失效。如果你始终把相关改动放在会话中提交,就能避免因部分更新导致的数据库不一致性。
数据库会话也可 回滚 。调用 db.session.rollback() 后,添加到数据库会话中的所有对象都会还原到它们在数据库时的状态。
修改行
在数据库会话上调用 add() 方法也能更新模型。我们继续在之前的 shell 会话中进行操作,
下面这个例子把 "Admin" 角色重命名为 "Administrator" :
>>> admin_role.name = 'Administrator'
>>> db.session.add(admin_role)
>>> db.session.commit()
删除行
数据库会话还有个 delete() 方法。下面这个例子把 "Moderator" 角色从数据库中删除:
>>> db.session.delete(mod_role)
>>> db.session.commit()
注意,删除与插入和更新一样,提交数据库会话后才会执行。
查询行
1.Flask-SQLAlchemy 为每个模型类都提供了 query 对象。最基本的模型查询是取回对应表中的所有记录:
>>> Role.query.all()
[
>>> User.query.all()
[
2.使用过滤器可以配置 query 对象进行更精确的数据库查询。下面这个例子查找角色为"User" 的所有用户:
>>> User.query.filter_by(role=user_role).all()
[
3.若要查看 SQLAlchemy 为查询生成的原生 SQL 查询语句,只需把 query 对象转换成字符串:
>>> str(User.query.filter_by(role=user_role))
'SELECT users.id AS users_id, users.username AS users_username,
users.role_id AS users_role_id FROM users WHERE :param_1 = users.role_id'
4.如果你退出了 shell 会话,前面这些例子中创建的对象就不会以 Python 对象的形式存在,而
是作为各自数据库表中的行。如果你打开了一个新的 shell 会话,就要从数据库中读取行,
再重新创建 Python 对象。下面这个例子发起了一个查询,加载名为 "User" 的用户角色:
>>> user_role = Role.query.filter_by(name='User').first()
5.filter_by() 等过滤器在 query 对象上调用,返回一个更精确的 query 对象。多个过滤器可以一起调用,直到获得所需结果。下表列出了可在 query 对象上调用的常用过滤器。完整的列表参见 SQLAlchemy 文档
(http://docs.sqlalchemy.org)。
常用的SQLAlchemy查询过滤器
过滤器 说 明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit() 使用指定的值限制原查询返回的结果数量,返回一个新查询
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询
6.在查询上应用指定的过滤器后,通过调用 all() 执行查询,以列表的形式返回结果。除了all() 之外,还有其他方法能触发查询执行。下表 列出了执行查询的其他方法。
最常使用的SQLAlchemy查询执行函数
方 法 说 明 all() 以列表形式返回查询的所有结果 first() 返回查询的第一个结果,如果没有结果,则返回 None first_or_404() 返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应 get() 返回指定主键对应的行,如果没有对应的行,则返回 None get_or_404() 返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错误响应 count() 返回查询结果的数量 paginate() 返回一个 Paginate 对象,它包含指定范围内的结果