flask-sqlalchemy总结

Flask-SQLAlchemy是一个Flask扩展,简化了在Flask程序中使用SQLAlchemy的操作。SQLAlchemy是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy提供了高层ORM,也提供了使用数据库原生SQL的低层功能。

1 安装

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

2 配置

  • 程序使用的数据库URL必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI键中。
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password@127.0.0.1:3306/test'
  • 其他

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

配置选项

说明

SQLALCHEMY_DATABASE_URI

连接数据库。示例:mysql://username:password@host/post/db?charset=utf-8

SQLALCHEMY_BINDS

一个将会绑定多种数据库的字典。 更多详细信息请看官文 绑定多种数据库.

SQLALCHEMY_ECHO

调试设置为true

SQLALCHEMY_POOL_SIZE

数据库池的大小,默认值为5。

SQLALCHEMY_POOL_TIMEOUT

连接超时时间

SQLALCHEMY_POOL_RECYCLE

自动回收连接的秒数。

SQLALCHEMY_MAX_OVERFLOW

控制在连接池达到最大值后可以创建的连接数。当这些额外的 连接回收到连接池后将会被断开和抛弃。

SQLALCHEMY_TRACK_MODIFICATIONS

如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它。

  • 连接数据库

不同的数据库采用不同的引擎连接语句:

(1)MySQL: mysql://username:password@hostname/database
(2)SQLite(Unix): sqlite:////absolute/path/to/database
(3)SQLite(Windows): sqlite:///c:/absolute/path/to/database
(4)Oracle: oracle://username:password@127.0.0.1:3306/database

参考代码如下:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password@127.0.0.1:3306/test'

# 设置每次请求结束后会自动提交数据库的改动
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

# 查询时显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)

3 定义模型

在ORM中,模型一般是一个Python类,类中的属性对应数据库表中的列。
Flask-SQLAlchemy创建的数据库实例为模型提供了一个基类以及一系列辅助类和辅助函数,可用于定义模型的结构。

3.1 常用的sqlalchemy字段类型

数据类型

说明

Integer

整型

String

字符串

Text

文本

DateTime

日期

Float

浮点型

Boolean

布尔值

PickleType

存储一个序列化( Pickle )后的Python对象

LargeBinary

巨长度二进制数据

3.2 常用的sqlalchemy字段属性

属性名

属性说明

primary_key

如果为True,代表字段为主键

unique

如果为True,该字段值唯一

index

如果为True,为该列创建索引

nullable

如果为True,允许为空值;为False,不允许有空值

default

设置字段默认值

3.3 常用的sqlalchemy关系选项

选项

说明

backref

在关系表中添加反向引用

secondary

指定多对多关系表的名字

primaryjoin

指定两个模型间的连接条件

secondaryjoin

指定多对多关系中二级连接条件

order_by

指定关系中的排列顺序

uselist

如果设为 Fales,不使用列表,而使用标量值

lazy

指定如何加载相关记录。可选值如下 :

select(首次访问时按需加载)

immediate(源对象加载后就加载)

joined(加载记录,但使用联结)

subquery(立即加载,但使用子查询)

noload(永不加载)

dynamic(不加载记录,但提供加载记录的查询)

参考代码如下:

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    user = db.relationship('User', backref='role')

    def __repr__(self):
        return '<Role %r>' % self.name


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True, index=True)
    email = db.Column(db.String(64), unique=True)
    pswd = db.Column(db.String(64))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return 'User:%s' % self.name

4 表的映射

创建好表后需要映射到数据库中,这里需要用到flask-migrate库。下面是启动文件manage.py

# -*- coding: UTF-8 -*-
from flask_script import Manager, Server
from flask_migrate import Migrate, MigrateCommand
from info import create_app, db, models

# development/production
app = create_app('development')
# 接管app
manager = Manager(app)
# 将 app 与 db 关联
Migrate(app, db)
# 将迁移命令添加到manager中
manager.add_command('db', MigrateCommand)

if __name__ == '__main__':
    manager.add_command('start', Server(port=8000, use_debugger=True)) # 创建启动命令
    manager.run()

配置好启动文件后,进入项目根目录,在命令行输入以下代码:

> python manage.py db init
> python manage.py db migrate
> python manage.py db upgrade

5 操作数据库(orm)

在pycharm中python console交互式执行shell。

>>> from manage import app, db
>>> app.app_context().push()
>>> from info.models import User
>>> User.query.all()
[<User 1>]

5.1 创建表

进入flask shell终端中

>>> from info import db
>>> db.create_all()
>>>

5.2 删除表

进入flask shell终端中

>>> from info import db
>>> db.drop_all()
>>>

5.3 增加数据

# 增加
use = User(id,username,password)
db.session.add(use)
 
# 增加多条
use1 = User(id1,username1,password1)
use2 = User(id2,username2,password2)
db.session.addall([use1, use2])

# 提交保存到数据库中
db.session.commit()

5.4 查询数据

# 查询全部
>>> User.query.all()
# 主键查询
>>> User.query.get(1)

# 条件查询
>>> User.query.filter_by(username='name').first()
>>> User.query.filter(User.username='name').first()

# 多条件查询
>>> from sqlalchemy import or_, and_, any_
>>> User.query.filter_by(and_(User.username =='name',User.password=='passwd'))

# 比较查询
>>> User.query.filter(User.id.__lt__(5)) # 小于5
>>> User.query.filter(User.id.__le__(5)) # 小于等于5
>>> User.query.filter(User.id.__gt__(5)) # 大于5
>>> User.query.filter(User.id.__ge__(5)) # 大于等于5

# in查询
User.query.filter(User.username.in_('A','B','C','D'))

# 排序
>>> User.query.order_by('age') # 按年龄排序,默认升序,在前面加-号为降序'-age'

# 限制查询
>>> User.query.filter(age=18).offset(2).limit(3)  # 跳过二条开始查询,限制输出3条

# join多表查询:
>>> User.query.filter_by(env_id=env_id,id=id).join(Environments, User.env_id == Environments.id).first_or_404()

# count返回数量
>>> User.query.filter_by(username='name').count()

# 分组
>>> from sqlalchemy import func
>>> db.session.query(User, func.count(User.id)).group_by(User.username).all()
[(<User 1>, 1)]

5.5 优化查询

>>> from sqlalchemy.orm import load_only
>>> from info.models import User

>>> # 只查询指定字段
>>> User.query.options(load_only(User.username, User.mobile)).filter_by(id=1).first()

5.6 修改数据

方式一:

>>> # 根据条件查询一行数据
>>> admin_role = Role.query.filter_by(role_name='Amdmin').first()
>>> # 修改数据
>>> admin_role.role_name = 'Admin'
>>> db.session.add(admin_role)
>>> db.session.commit()

方式二:

>>> User.query.filter_by(User.username='name').update({'password':'newdata'})
>>> db.session.commit()

5.7 删除数据

db.session.delete(User)
db.session.commit()

>>> User.query.filter_by(User.username='name').delete()
>>> db.session.commit()

5.8 事务

一个事务或多个事务 ,要么都执行成功,要么都不执行

try:
    user = User(username='admin', mobile='18100000000')
    db.session.add(user)
    db.session.flush()  # 将db.session记录的sql传到数据库中执行
    profile = UserProfile(id=user.id)
    db.session.add(profile)
    db.session.commit()
except:
    db.session.rollback()  # 事务回滚