浅谈Flask-sqlalchemy

最近看了点Flask,不同于Django的一小点,Flask没有自带ORM(其实大部分功能都没有),不过如果需要操作数据库,可以使用第三方库flask-sqlalchemy ,大概用法与Django ORM 如出一辙。

配置sqlalchemy

首先当然是安装依赖啦pip install flask-sqlalchemy, 然后就是配置数据库

1
2
3
4
5
6
7
8
9
10
import os

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'+os.path.join(base_dir,'database.sqlite')

db = SQLAlchemy(app)

如果使用其他数据库其实就是改下SQLALCHEMY_DATABASE_URI, 以MySQL 为例:

1
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://f{username}:{password}@{hostname}/{database}'

定义模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from src import db


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

def __str__(self):
return self.username


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

def __str__(self):
return self.name

如果想使用继承id图方便,外键部分需要使用primaryjoin一个坑

其中 __tablename__可以重新定义表在库中的名字,db.Column() 为一个字段,第一个参数为字段类型如db.String(32)为字符串类型, primary_key=True字段为主键,(这里与Django orm 中会默认生成一个id作为主键不同), 其他类型 unique=True为唯一键,index=True为字段建立索引,default=0设置一个默认值,nullable=True该字段可为null

数据库关系

数据库关系一般分为3种, 一对多,一对一, 多对多

一对多

如果需要构建一对多关系,需要添加外键

1
2
3
4
5
6
7
class User(BaseModel):
#...
role_id = db.Column(db.Integer, db.ForeignKey('role.id'))

class Role(BaseModel):
#...
users = db.realationship('User', backref='role')

这里给User表加了一个关联Role表的外键, 其中backref给role表做了一个反向引用

一对一

如果是想将两表构成一对一只需要一步,realationship 中将uselist=False

1
users = db.realationship('User', uselist=False, backref='role')

多对多

多对多关系需要使用第三张表来建立关系,此处用官方文档的例子占个坑

1
2
3
4
5
6
7
8
9
10
11
12
tags = db.Table('tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True),
db.Column('page_id', db.Integer, db.ForeignKey('page.id'), primary_key=True)
)

class Page(db.Model):
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=tags, lazy='subquery',
backref=db.backref('pages', lazy=True))

class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)

数据库迁移

新建表或新增字段之后,需要做的第一步就是迁移数据库,在Django中两条命令即可

1
2
python manage.py migrate
python manage.py makemigrations

然而在Flask 中也不自带这些命令,如果用最原始的方式创建表,需要shell 中执行

1
2
3
4
from src import db
db.create_all() # 创建所有表
db.drop_all() # 有更新需要删表重新建
db.create_all()

这样操作最大的问题不是麻烦,而是需要更新把原来的数据都删光了,感觉蠢的一匹~

所以这里要使用另一个第三方库Flask-Migrate,大致的操作跟Django差不多,

  1. 安装依赖
1
pip install flask-migrate
  1. 第一步需要去添加配置
1
2
3
4
from flask_migrate import Migrate

# ...
migrate = Migrate(app)
  1. 第一次需要初始化项目,创建迁移仓库,会生成一个存放迁移文件的migrations文件夹
1
flask db init
  1. 每当有数据库更新时,需要创建迁移脚本
1
flask db migrate -m 'migrate message'
  1. 将迁移应用到数据库中
1
flask db upgrade
  1. 如果最后一次迁移未达到预期效果,可以还原上一次改动
1
2
flask db downgrade
# 删了最后一次的迁移文件,重新改动数据库,再重复3,4动作

数据库操作

大部分的增删改查操作,跟 Django ORM都没啥大区别,无非就是一些语法, 最主要应该就是sqlalchemy 需要db.session.add()db.session.commit()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 增
role = Role(name='admin')
user1 = User(username='ZmJ', role=role)
user2 = User(username='zmj'role=role)
db.session.add_all([user1, user2])
db.session.commit()

# 查
user1 = User.query.filter_by(username='ZmJ').first()
user2 = User.query.filter_by(username='zmj').first()

# 改
user1.username = 'Flask'
db.session.add(user1)
db.session.commit()

# 删
db.session.delete(user2)
db.session.commit()

具体内容可查看官方文档

flask-migrate官方文档

flask-sqlalchemy官方文档