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 '<Role %r>' % 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 '<User %r>' % 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()

[<Role u'Administrator'>, <Role u'User'>]

>>> User.query.all()
[<User u'john'>, <User u'susan'>, <User u'david'>]

2.使用过滤器可以配置 query 对象进行更精确的数据库查询。下面这个例子查找角色为"User" 的所有用户:

>>> User.query.filter_by(role=user_role).all()
[<User u'susan'>, <User u'david'>]

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 对象,它包含指定范围内的结果

Flask开发系列之数据库操作的更多相关文章

  1. Flask开发系列之Flask+redis实现IP代理池

    Flask开发系列之Flask+redis实现IP代理池 代理池的要求 多站抓取,异步检测:多站抓取:指的是我们需要从各大免费的ip代理网站,把他们公开的一些免费代理抓取下来:一步检测指的是:把这些代 ...

  2. openresty开发系列28--openresty中操作mysql

    openresty开发系列28--openresty中操作mysql Mysql客户端   应用中最常使用的就是数据库了,尤其mysql数据库,那openresty lua如何操作mysql呢?   ...

  3. Flask开发系列之Web表单

    Flask开发系列之Web表单 简单示例 from flask import Flask, request, render_template app = Flask(__name__) @app.ro ...

  4. Flask开发系列之模板

    Flask开发系列之模板 本文对<FlaskWeb开发:基于python的Web应用开发实战>模板一节做的总结. Jinja2模板引擎 模板 模板是一个包含响应文本的文件,其中包含用占位变 ...

  5. Flask开发系列之快速入门

    Flask开发系列之快速入门 文档 一个最小的应用 调试模式 路由 变量规则 构造 URL HTTP 方法 静态文件 模板渲染 访问请求数据 环境局部变量 请求对象 文件上传 Cookies 重定向和 ...

  6. Flask开发系列之初体验

    Flask开发初探 介绍 在日常开发中,如果需要开发一个小型应用或者Web接口,一般我是极力推崇Flask的,主要是因为其简洁.扩展性高. 从这篇文章开始,我会写一个关于Flask的系列文章,通过多个 ...

  7. Code First开发系列之数据库迁移

    返回<8天掌握EF的Code First开发>总目录 本篇目录 开启并运行迁移 使用迁移API 应用迁移 给已存在的数据库添加迁移 EF的其他功能 本章小结 自我测试 本系列的源码本人已托 ...

  8. Sql Server系列:数据库操作

    1 创建数据库 1.1 CREATE DATABASE语法 CREATE DATABASE database_name [ ON [ PRIMARY ] <filespec> [ ,... ...

  9. Flask学习之旅--数据库

    一.写在前面 在Web开发中,数据库操作是很重要的一部分,因为网站的很多重要信息都保存在数据库之中.而Flask在默认情况下是没有数据库.表单验证等功能的,但是可以用Flask-extension为W ...

随机推荐

  1. (转)php中字符过滤

    有时候为了安全起见,我们需要对用户输入的字符串进行转义       文章中有不正确的或者说辞不清的地方,麻烦大家指出了--- 与PHP字符串转义相关的配置和函数如下: 1.magic_quotes_r ...

  2. hibernate注解@manytoone,@onetomany

    一.一对多(@onetomany) 1.单向一对多模型 假设通过一个客户实体可以获得多个地址信息.对于一对多的实体关系而言,表结构有两种设计策略,分别是外键关联和表关联. (1) 映射策略---外键关 ...

  3. 利用python的图像分块与拼接

    import os import matplotlib.pyplot as plt import cv2 import numpy as np def divide_img(img_path, img ...

  4. What exactly is the parameter e (event) and why pass it to JavaScript functions?

    What exactly is the parameter e (event) and why pass it to JavaScript functions? 问题 Well, when I lea ...

  5. ORACLE 11GR2常用参数(含隐含参数)设置

    ORACLE 11GR2常用参数(含隐含参数)设置如下: alter system set "_PX_use_large_pool" = true scope=spfile;alt ...

  6. 1.2.1 Maven到底是什么鬼

    解释之前,提1个小问题. 1.1.假如你正在Eclipse下开发两个Java项目,姑且把它们称为A.B,其中A项目中的一些功能依赖于B项目中的某些类,那么如何维系这种依赖关系的呢? 很简单,这不就是跟 ...

  7. Appium+python自动化-输入中文

    一.定位搜索 1.打开淘宝点击搜索按钮,进入到搜索页面 2.然后定位到搜索框后用sendkeys方法输入‘hao’,这里定位元素使用uiautomatorviewer工具即可 3.脚本如下,输入的是英 ...

  8. python字符串判断

    s为字符串 s.isalnum() 所有字符都是数字或者字母 s.isalpha() 所有字符都是字母 s.isdigit() 所有字符都是数字 s.islower() 所有字符都是小写 s.isup ...

  9. MySQL 树形结构 根据指定节点 获取其下属的所有子节点(包含路径上的枝干节点和叶子节点)

    背景说明 需求:MySQL树形结构, 根据指定的节点,获取其下属的所有子节点(包含路径上的枝干节点和叶子节点) 枝干节点:如果一个节点下还有子节点,则为枝干节点. 叶子节点:如果一个节点下不再有子节点 ...

  10. 配置linux系统时区---解决ntp同步完时间不准问题

    ntp配置完成后时间仍然不准有下面两种情况: ntp服务端配置完ntp服务器后,查看时间和百度的时间不一样按照下面解决 ntp客户端同步完ntp服务器后,查看客户端的时间和百度不一致,按照下面解决 1 ...