Flask 模型操作|Python 主题月

661 阅读4分钟

本文正在参加「Python主题月」,详情查看活动链接

导语

简单总结相关Flask模型层用到的插件:Flask-SQLAlchemy和Flask-Migrate,分别用于操作数据库以及跟踪数据库迁移;归纳开发过程中会使用到的几个场景和常用的方法。关于Flask-SQLAlchemy一些复杂的增删改查操作涉及到比较多的场景,本文暂不涉及。

关于ORM

通过ORM框架,可以方便快捷的进行数据库操作,同时提高规范性,降低操作性,提高开发效率。同时具备支持多种类型数据库,即提供了高层ORM操作,同时也可以使用底层的SQL原生功能。

常见Python ORM框架:

  • Django's ORM(易用易上手,缺点性能问题)
  • SqlAlchemy(灵活设计,缺点学习成本高)

Flask-Sqlalchemy扩展

基于SqlAlchemy,Flask-Sqlalchemy扩展简化了Flask项目中使用的SqlAlchemy的操作。

Flask-Sqlalchemy简单应用

from flask import Flask
from flask-sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)


class User(db.Model):
    __table__name = "user"
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

备注:

  • app的应用配置项SQLALCHEMY_DATABASE_URI指定了SQLAlchemy所要操作的数据库;
  • db对象是SQLAlchemy类的实例,表示程序使用的数据库;
  • 定义的User模型对应着数据库中的表,__tablename__定义了在数据库中使用的表明,如果该变量没有定义,Flask-SQLAlchemy会使用一个默认的名字;

Flask-Sqlalchemy表初始化:

db.create_all()

Flask-Sqlalchemy表操作:

admin = User('admin', 'admin@example.com')
guest = User('guest', 'guest@example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()


user = User.query.filter_by(username="admin").first()
print(user.id, user.username, user.email)

备注:

  • 将需要提交的数据提交到会话后,最后通过db.session.commit()提交事务,最终才会将数据写入到数据库中;

进阶使用

Flask-SQLAlchemy扩展能够识别的配置项:

  • SQLALCHEMY_DATABASE_URI:用于连接数据库;
  • SQLALCHEMY_BINDS:用于SQLAlchemy绑定多个数据库;
  • SQLALCHEMY_ECHO:设置为True,SQLAlchemy将会记录所有发到标准输出(stderr)的语句,主要用于调试,默认为False;
  • SQLALCHEMY_POOL_SIZE:数据库连接池大小;
  • SQLALCHEMY_POOL_TIMEOUT:数据库连接池超时时间;
  • SQLALCHEMY_POOL_RECYCLE:自动回收连接的秒数,对于Mysql,Mysql会自动回收闲置超过八小时的连接,Flask-SQLAlchemy默认回收超过两小时的连接;
  • SQLALCHEMY_TRACK_MODIFICATIONS:Flask-SQLAlchemy将会追踪对象的修改并且发送信号,将会消耗内存,默认为True,不需要可关闭;

绑定多个数据库

# -*- coding: utf-8 -*-

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config["SQLALCHEMY_BINDS"] = {"user":"sqlite:///user.db", "film": "sqlite:///film.db"}
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_ECHO"] = True
db = SQLAlchemy(app)


class User(db.Model):
    __bind_key__ = "user"
    __tablename__ = "user"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)    
    user_name = db.Column(db.String(20), unique=True)
    user_email = db.Column(db.String(40), unique=True)

    def __init__(self):
        self.session = db.session

    def set_user(self, user_name, user_email):
        self.user_name = user_name
        self.user_email = user_email
        self.session.add(self)
        self.session.commit()


if __name__ == "__main__":
    db.create_all(bind="user")
    user = User()
    user.set_user("wangyangming", "wangyangming@email.com")

备注:

  • SQLALCHEMY_BINDS配置项在字典中可以声明多个数据库连接;
  • User模型中__bind_key__属性用于指定绑定连接;
  • db.create_all()可以作用所有声明的绑定,也可作用指定绑定,drop_all方法也是一样;

声明模型(一对多关系)

# -*- coding: utf-8 -*-

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
user = 'root'
password = 'root'
database = 'test'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://%s:%s@127.0.0.1:3306/%s?charset=gbk' % (user, password, database)
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_ECHO"] = True
db = SQLAlchemy(app)


class User(db.Model):
    __tablename__ = "user"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)    
    user_name = db.Column(db.String(20), unique=True)
    user_addr = db.relationship("Address", backref="user", lazy='dynamic')

    def __init__(self):
        self.session = db.session

    def set_user(self, user_name, user_email):
        self.user_name = user_name
        addr = Address(email=user_email, user=self)
        self.session.add(self)
        self.session.add(addr)
        self.session.commit()

class Address(db.Model):
    __tablename__ = "address"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    email = db.Column(db.String(40), unique=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

if __name__ == "__main__":
    user = User()
    user.set_user("wangyangming", "wangyangming@email.com")
    address = Address.query.filter_by(email="wangyangming@email.com").first()
    if address:
        print(address.id)
        print(address.user.user_name)

备注:

  • db.relationship函数定义关联的表,backref为Address提供一个新的属性,可以使用Address.user获取使用该地址的人,lazy可以决定SQLAlchemy从什么时候获取数据,'dynamic' 在有多条数据的时候是特别有用的,不是直接加载这些数据;
  • 外键通过ForeignKey单独声明;

Flask-Migrate扩展

处理SQLAlchemy数据库迁移的扩展,通过Flask命令行接口对数据库进行操作。对数据库升级和降级。

Flask-Migrate使用:

from flask_migrate import Migrate
migrate = Migrate(app, db)

Flask-Migrate常用命令:

flask db init
flask db migrate
flask db upgrade

命令解析:

  • init:新建一个名字为migrations的文件夹,并且记录一个数据库版本号,一份保留在migrations中,一份保存在数据库中(新建一张名字为alembic_version的表来保存)
  • migrate:在migrations文件夹中生成迁移文件。(迁移脚本不会检测models 的所有变更, Alembic 目前无法检测表名修改,列名修改)
  • upgrade:将修改应用到数据库中。

参考

www.pythondoc.com/flask-sqlal…
www.cnblogs.com/cwp-bg/p/88…