前面的章节中我们已经学习了如何建立模型和关系,接下来我们学习如何使用模型的最好方法是在Python shell 中实际操作。并将介绍最常用的数据库操作。
一.创建表
首先,我们要让Flask-SQLAlchemy 根据模型类创建数据库。方法是使用db.create_all()函数
(venv) $ python hello.py shell
>>> from hello import db
>>> db.create_all()
查询mysql数据库,我们会发现已经创建好的users和roles表,如果数据库表已经存在于数据库中,那么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)
模型的构造函数接受的参数是使用关键字参数指定的模型属性初始值。注意,role 属性也可使用,虽然它不是真正的数据库列,但却是一对多关系的高级表示。这些新建对象的id属性并没有明确设定,因为主键是由Flask-SQLAlchemy 管理的。现在这些对象只存在于
Python 中,还未写入数据库。因此id 尚未赋值:
>>> print(admin_role.id)
None
>>> print(mod_role.id)
None
通过数据库会话管理对数据库所做的改动,在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)
为了把对象写入数据库,我们要调用commit() 方法提交会话:
>>> db.session.commit()
然后去数据库中查询,就能查询到插入的记录了。
mysql> select * from roles;
+----+---------------+
| id | name |
+----+---------------+
| | Administrator |
| | Mode |
| | User |
+----+---------------+
数据库会话能保证数据库的一致性。提交操作使用原子方式把会话中的对象全部写入数据库。如果在写入会话的过程中发生了错误,整个会话都会失效。如果你始终把相关改动放在会话中提交,就能避免因部分更新导致的数据库不一致性。数据库会话也可回滚。调用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()
注意,删除与插入和更新一样,提交数据库会话后才会执行。
五.查询行
Flask-SQLAlchemy 为每个模型类都提供了query 对象。最基本的模型查询是取回对应表中的所有记录:
>>> Role.query.all()
[<Role u'Administrator'>, <Role u'User'>]
>>> User.query.all()
[<User u'john'>, <User u'susan'>, <User u'david'>]
使用过滤器可以配置query 对象进行更精确的数据库查询。下面这个例子查找角色为"User" 的所有用户
>>> User.query.filter_by(role=user_role).all()
[<User u'susan'>, <User u'david'>]
若要查看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'
如果你退出了shell 会话,前面这些例子中创建的对象就不会以Python 对象的形式存在,而是作为各自数据库表中的行。如果你打开了一个新的shell 会话,就要从数据库中读取行,再重新创建Python 对象。下面这个例子发起了一个查询,加载名为"User" 的用户角色:
user_role = Role.query.filter_by(name='User').first()
filter_by() 等过滤器在query 对象上调用,返回一个更精确的query 对象。多个过滤器可以一起调用,直到获得所需结果。下面列出了Query对象上调用的常用过滤器
过滤器 | 说明 |
filter() | 把过滤器添加到原查询上,返回一个新查询 |
filter_by() | 把等值过滤器添加到原查询上,返回一个新查询 |
limit() | 使用指定的值限制原查询返回的结果数量,返回一个新查询 |
offset() | 偏移原查询返回的结果,返回一个新查询 |
order_by() | 根据指定条件对原查询结果进行排序,返回一个新查询 |
group_by() | 根据指定条件对原查询结果进行分组,返回一个新查询 |
在查询上应用指定的过滤器后,通过调用all() 执行查询,以列表的形式返回结果。除了all() 之外,还有其他方法能触发查询执行。下表 列出了执行查询的其他方法。
all() | 以列表形式返回查询的所有结果 |
first() | 返回查询的第一个结果,如果没有结果,则返回None |
first_or_404() | 返回查询的第一个结果,如果没有结果,则终止请求,返回404 错误响应 |
get() | 返回指定主键对应的行,如果没有对应的行,则返回None |
get_or_404() | 返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回404 错误响应 |
count() | 返回查询结果的数量 |
paginate() | 返回一个Paginate 对象,它包含指定范围内的结果 |