Python 数据库框架

大多数的数据库引擎都有对应的 Python 包,包括开源包和商业包。Flask 并不限制你使用何种类型的数据库包,因此可以根据自己的喜好选择使用 MySQL、Postgres、SQLite、RedisMongoDB 或者 CouchDB。

如果这些都无法满足需求,还有一些数据库抽象层代码包供选择,例如SQLAlchemyMongoEngine。你可以使用这些抽象包直接处理高等级的 python 对象,而不用处理如表、文档或查询语言此类的数据库实体。

选择数据库框架的因素:

  • 易用性。抽象层,也称为对象关系映 射(Object-Relational Mapper,ORM) 或 对 象 文 档 映 射(Object-Document Mapper,ODM),在用户不知觉的情况下把高层的面向对象操作转换成低层的数据库指令。
  • 性能。ORM 和 ODM 把对象业务转换成数据库业务会有一定的损耗。真正的关键点在于如何选择一个能直接操作低层数据库的抽象层,以防特定的操作需要直接使用数据库原生指令优化。
  • 可移植性。必须考虑其是否能在你的开发平台和生产平台中使用。
  • Flask集成度

Flask-SQLAlchemy 管理数据库

  • 安装
pip install flask-sqlalchemy
  • 1
  • 1

使用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

SQLite 数 据 库 不 需 要 使 用 服 务 器, 因 此 不 用 指 定 hostname 、 username 和 password 。URL 中的 database 是硬盘上文件的文件名。

  • 配置
    程序使用的数据库 URL 必须保存到 Flask 配置对象的 SQLALCHEMY_DATABASE_URI 键中

配置对象中还有一个很有用的选项,即 SQLALCHEMY_COMMIT_ON_TEARDOWN 键,将其设为 True时,每次请求结束后都会自动提交数据库中的变动

from flask.ext.sqlalchemy import SQLAlchemy
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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 定义模型
class Role(db.Model):
__tablename__ = 'roles'#__tablename__ 定义在数据库中使用的表名
id = db.Column(db.Integer, primary_key=True)#primary_key如果设为 True ,这列就是表的主键.如果没有定义 __tablename__ ,SQLAlchemy 会使用一个默认名字
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

__repr__&__str__

最常用的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 二进制文件

最常使用的SQLAlchemy列选项

选项名 说 明
primary_key 如果设为 True ,这列就是表的主键
unique 如果设为 True ,这列不允许出现重复的值
index 如果设为 True ,为这列创建索引,提升查询效率
nullable 如果设为 True ,这列允许使用空值;如果设为 False ,这列不允许使用空值
default 为这列定义默认值

关系表达

关系型数据库使用关系把不同表中的行联系起来。

  • 一对多
class Role(db.Model):
# ...
users = db.relationship('User', backref='role')#添加到 Role 模型中的 users 属性代表这个关系的面向对象视角。对于一个 Role 类的实例,其 users 属性将返回与角色相关联的用户组成的列表。db.relationship() 的第一个参数表,如果模型类尚未定义,可使用字符串形式指定。db.relationship() 中的 backref 参数向 User 模型中添加一个 role 属性,从而定义反向关系。这一属性可替代 role_id 访问 Role 模型,此时获取的是模型对象
class User(db.Model):
# ...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))#关系使用 users 表中的外键连接了两行。添加到 User 模型中的 role_id 列被定义为外键,就是这个外键建立起了关系。传给 db.ForeignKey() 的参数 'roles.id' 表明,这列的值是 roles 表中行的 id 值。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

db.relationship() 都能自行找到关系中的外键,但有时却无法决定把哪一列作为外键。如果 User 模型中有两个或以上的列定义为 Role 模型的外键,SQLAlchemy 就不知道该使用哪列。如果无法决定外键,你就要为 db.relationship() 提供额外参数,从而确定所用外键

常用的SQLAlchemy关系选项

选项名 说 明
backref 在关系的另一个模型中添加反向引用
primaryjoin 明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定
lazy 指定如何加载相关记录。可选值有 select (首次访问时按需加载)、 immediate (源对象加载后就加载)、 joined (加载记录,但使用联结)、 subquery (立即加载,但使用子查询),noload (永不加载)和 dynamic (不加载记录,但提供加载记录的查询)
uselist 如果设为 Fales ,不使用列表,而使用标量值
order_by 指定关系中记录的排序方式
secondary 指定 多对多 关系中关系表的名字
secondaryjoin SQLAlchemy 无法自行决定时,指定多对多关系中的二级联结条件
  • 一对一
    一对一关系可以用前面介绍的一对多关系表示,但调用 db.relationship() 时要把 uselist 设为 False ,把“多”变成“一”。

  • 多对多

tags = db.Table('tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
db.Column('page_id', db.Integer, db.ForeignKey('page.id'))
) class Page(db.Model):
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=tags,
backref=db.backref('pages', lazy='dynamic')) class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

数据库操作

  • 创建表
python hello.py shell
>>> from hello import db
>>> db.create_all()
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  • 删除表
db.drop_all()
  • 1
  • 1
  • 插入行
#创建对象,模型的构造函数接受的参数是使用关键字参数指定的模型属性初始值。
admin_role = Role(name='Admin')
user_role = Role(name='User')
user_susan = User(username='susan', role=user_role)#role 属性也可使用,虽然它不是真正的数据库列,但却是一对多关系的高级表示。
user_john = User(username='john', role=admin_role)
#这些新建对象的 id 属性并没有明确设定,因为主键是由 Flask-SQLAlchemy 管理的。
print(admin_role.id)#None
#通过数据库会话管理对数据库所做的改动,在 Flask-SQLAlchemy 中,会话由 db.session 表示。
##首先,将对象添加到会话中
db.session.add(admin_role)
db.session.add(user_role)
db.session.add(user_susan)
db.session.add(user_john)
#简写:db.session.add_all([admin_role, user_role, user_john, user_susan])
##通过提交会话(事务),将对象写入数据库
db.session.commit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

会话提交

数据库会话能保证数据库的一致性。提交操作使用原子方式把会话中的对象全部写入数据库。如果在写入会话的过程中发生了错误,整个会话都会失效。
数据库会话也可 回滚 。调用 db.session.rollback() 后,添加到数据库会话中的所有对象都会还原到它们在数据库时的状态。

  • 修改行
admin_role.name = 'Administrator'
db.session.add(admin_role)
session.commit()
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  • 删除行
db.session.delete(mod_role)
session.commit()
  • 1
  • 2
  • 1
  • 2
  • 查询行

    • 查询全部。Role.query.all()
    • 条件查询(使用过滤器)。User.query.filter_by(role=user_role).all()
    user_role = Role.query.filter_by(name='User').first()#filter_by() 等过滤器在 query 对象上调用,返回一个更精确的 query 对象。
    • 1
    • 1

    常用过滤器

过滤器 说 明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit() 使用指定的值限制原查询返回的结果数量,返回一个新查询
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询

最常使用的SQLAlchemy查询执行函数

方 法 说 明
all() 以列表形式返回查询的所有结果
first() 返回查询的第一个结果,如果没有结果,则返回 None
first_or_404() 返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应
get() 返回指定主键对应的行,如果没有对应的行,则返回 None
get_or_404() 返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错误响应
count() 返回查询结果的数量
paginate() 返回一个 Paginate 对象,它包含指定范围内的结果
  • 关系查询


    #执行 user_role.users 表达式时,隐含的查询会调用 all() 返回一个用户列表。 query 对象是隐藏的,因此无法指定更精确的查询过滤器。 users = user_role.users #修改了关系的设置,加入了 lazy = 'dynamic' 参数,从而禁止自动执行查询 class Role(db.Model):
    users = db.relationship('User', backref='role', lazy='dynamic') #顺序排列 user_role.users.order_by(User.username).all()
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

在视图函数中操作数据库

@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.name.data).first()
if user is None:
user = User(username = form.name.data)
db.session.add(user)
session['known'] = False
else:
session['known'] = True
session['name'] = form.name.data
form.name.data = ''
return redirect(url_for('index'))
return render_template('index.html', form = form, name = session.get('name'), known = session.get('known', False))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

修改模板

{ % extends "base.html" % }
{ % import "bootstrap/wtf.html" as wtf % }
{ % block title % }Flasky{ % endblock % }
{ % block page_content % }
<div class="page-header">
<h1>Hello, { % if name % }{{ name }}{ % else % }Stranger{ % endif % }!</h1>
{ % if not known % }
<p>Pleased to meet you!</p>
{ % else % }
<p>Happy to see you again!</p>
{ % endif % }
</div>
{{ wtf.quick_form(form) }}
{ % endblock % }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

集成 Python shell

让 Flask-Script 的 shell 命令自动导入特定的对象

from flask.ext.script import Shell
def make_shell_context():
return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

make_shell_context() 函数注册了程序、数据库实例以及模型,因此这些对象能直接导入 shell

使用 Flask-Migrate 实现数据库迁移

创建迁移仓库

pip install flask-migrate
  • 1
  • 1

配置

from flask.ext.migrate import Migrate, MigrateCommand
# ...
migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

在维护数据库迁移之前,要使用 init 子命令创建迁移仓库

python hello.py db init
  • 1
  • 1

创建迁移脚本

python hello.py db migrate -m "initial migration"
  • 1
  • 1

更新数据库

python hello.py db upgrade
  • 1

原文连接:http://blog.csdn.net/sun_dragon/article/details/51719753

 

flask学习笔记(-操作数据库)的更多相关文章

  1. 10 python学习笔记-操作数据库(十)

    在功能.接口测试中,常常需要通过数据库的操作,来准备数据.检测环境及核对功能.接口的数据库操作是否正确. 在自动化测试中,就需要我们用代码连接数据库自动完成数据准备. 环境检查及数据库断言的功能.数据 ...

  2. Flask学习笔记:数据库迁移操作flask-script+alembic/flask-migrate

    数据库迁移是将代码中模型类(即表)的修改同步到数据库中, flask-sqlalchemy的模型类一旦使用create_all()映射到数据库中后,对这个模型类的修改(例如添加了一个新的字段)就不会再 ...

  3. Flask学习笔记:数据库ORM操作MySQL+pymysql/mysql-python+SQLAlchemy/Flask-SQLAlchemy

    Python中使用sqlalchemy插件可以实现ORM(Object Relationship Mapping,模型关系映射)框架,而Flask中的flask-sqlalchemy其实就是在sqla ...

  4. Mysql数据库学习笔记之数据库索引(index)

    什么是索引: SQL索引有两种,聚集索引和非聚集索引,索引主要目的是提高了SQL Server系统的性能,加快数据的查询速度与减少系统的响应时间. 聚集索引:该索引中键值的逻辑顺序决定了表中相应行的物 ...

  5. MongoDB学习笔记:MongoDB 数据库的命名、设计规范

    MongoDB学习笔记:MongoDB 数据库的命名.设计规范     第一部分,我们先说命名规范. 文档 设计约束 UTF-8 字符 不能包含 \0 字符(空字符),这个字符标识建的结尾 . 和 $ ...

  6. Python Flask学习笔记之模板

    Python Flask学习笔记之模板 Jinja2模板引擎 默认情况下,Flask在程序文件夹中的templates子文件夹中寻找模板.Flask提供的render_template函数把Jinja ...

  7. Python Flask学习笔记之Hello World

    Python Flask学习笔记之Hello World 安装virtualenv,配置Flask开发环境 virtualenv 虚拟环境是Python解释器的一个私有副本,在这个环境中可以安装私有包 ...

  8. springboot学习-jdbc操作数据库--yml注意事项--controller接受参数以及参数校验--异常统一管理以及aop的使用---整合mybatis---swagger2构建api文档---jpa访问数据库及page进行分页---整合redis---定时任务

    springboot学习-jdbc操作数据库--yml注意事项--controller接受参数以及参数校验-- 异常统一管理以及aop的使用---整合mybatis---swagger2构建api文档 ...

  9. Django学习笔记之数据库-模型的操作

    模型的操作 在ORM框架中,所有模型相关的操作,比如添加/删除等.其实都是映射到数据库中一条数据的操作.因此模型操作也就是数据库表中数据的操作. 添加模型 添加模型到数据库中.首先需要创建一个模型.创 ...

随机推荐

  1. cas如何去掉HTTPS认证?

    说明:默认情况下HTTP也是可以访问CAS SERVER的,但认证,登陆,退出等操作均没有任何的效果.所以必须作出下面的修改  1.进入WEB-INF\spring-configuration目录 打 ...

  2. xss测试用例小结

    <script>alert("跨站")</script> (最常用) <img scr=javascript:alert("跨站" ...

  3. 高性能WEB开发:Javascript自身执行效率

    Javascript中的作用域链.闭包.原型继承.eval等特性,在提供各种神奇功能的同时也带来了各种效率问题,用之不慎就会导致执行效率低下. 1.全局导入 我们在编码过程中多多少少会使用到一些全局变 ...

  4. 【ACM】Fighting for HDU

    #include <stdio.h> #include <stdlib.h> #define max 100 /* run this program using the con ...

  5. 【转载】Android控件属性大全

    控件属性: android属性 Android功能强大,界面华丽,但是众多的布局属性就害苦了开发者,下面这篇文章结合了网上不少资料, 第一类:属性值为true或falseandroid:layout_ ...

  6. Spark1.0.0 history server 配置

    在执行Spark应用程序的时候,driver会提供一个webUI给出应用程序的执行信息.可是该webUI随着应用程序的完毕而关闭port,也就是说,Spark应用程序执行完后,将无法查看应用程序的历史 ...

  7. Android性能优化的方方面面

    通常项目比较大的APP都面临着如下性能问题,APP启动慢.界面跳转慢.事件相应慢.滑动和动画卡顿.展现内容慢等,有的公司处理的很好,有的还有很大的优化空间,对于性能优化,怎么去做,我总结了一下性能优化 ...

  8. gensim自然语言处理(续)

    上一篇,已经实现了如何将一条语句在一个语料库中比较相似度, 发现运行的时候每次都要编译语料库,通过查找资料,可以一次性编译成预料库,存人文件 编译语料库代码 11_k.py import sysimp ...

  9. 算法笔记_076:蓝桥杯练习 结点选择(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 有一棵 n 个节点的树,树上每个节点都有一个正整数权值.如果一个点被选择了,那么在树上和它相邻的点都不能被选择.求选出的点的权值和最大是多 ...

  10. 前端工程化 ESlint 配置

    1.使用的标准 // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style extends ...