第五章 Flask中操作数据库(一)

一. Python数据库框架

        大多数数据库引擎都有对应的Python包,如:MySQL、SQLite、Redis、MongoDB等。此外还有一些数据库抽象层代码包供选择,如:SQLAlchemy和MongoEngine。选择数据库框架式,要考虑很多因素:

  • 易用性

       抽象层也成为对象关系映射(ORM)或对象文档映射(ODM),可以把高层的面向对象操作转换为底层的数据库指令。因此,相比数据库引擎,更具易用性。

  • 性能

       ORM和ODM把对象转换为数据库业务时会有一定损耗,但它们对生产效率的提升远远超过了这一丁点儿性能的降低。

  • 可移植性

       选择数据库时必须考虑其是否能在你的开发平台和生产平台中使用。可移植性还针对ORM和ODM,有些框架只为一种数据库引擎提供抽象层。但其它框架可能做了更高层的抽象,支持不同的数据库引擎,并使用相同的现象对象接口。如SQLAlchemy ORM支持MySQL/Postgres/SQLite数据库引擎。

  • Flask集成度

       使用集成了Flask的数据库框架可以简化配置和操作,《Flask Web开发》一书选择的数据库框架是Flask-SQLAlchemy,这个Flask扩展包装了SQLAlchemy框架。

二. 使用Flask-SQLAlchemy框架管理数据库

       SQLAlchemy提供了高层ORM,也提供了使用数据库原生SQL的底层功能,Flask-SQLAlchemy的安装:

pip install flask-sqlalchemy

Flask-SQLAlchemy数据库URL

数据库引擎 URL
MySQL mysql://username:password@hostname/database
Postgres postgresql://username:password@hostname/database
SQLite(Linux/macOS) sqlite:////absolute/path/to/database
SQLite(Wondows) sqlite:///c:/absolute/path/to/database

       SQLite数据库没有服务器,因此不用指定hostname/passwordd/username,URL中的database是磁盘中的文件名。 应用使用的数据库URL保存在Flask配置对象的SQLALCHEMY_DATABASE_URI键中。Flask-SQLAlchemy建议把SQLALCHEMY_TRACK_MODIFICATIONS键设为False,以便在不需要跟踪对象变化时降低内存消耗。

app.py 配置数据库:

import os
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 配置SQLite数据库
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

db对象是SQLAlchemy类的实例,表示应用使用的数据库。 

三. 定义模型

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

app.py 添加模型定义:

class Role(db.Model):
    """定义角色模型"""
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    # 关联的另一端是哪个模型
    users = db.relationship('User', backref='role')

    def __repr__(self):
        return '' % 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)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return '' % self.username

说明:

  • 类变量__tablename__定义在数据库中使用的表名;
  • 模型的属性(表的列)都定义为db.Column()类的实例,其第一个参数是数据库列(模型属性)的类型(详见表5-2);
  • db.Column()的其余参数指定属性的配置选项(详见表5-3);
  • __repr__()方法返回一个具有可读性的字符串表示模型,供调试和测试时使用;

表5-2 最常用的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 boolean 布尔值
Date datetime.date 日期
Time datetime.time 时间
DateTime datatime.datetime 日期和时间
Interval datetime.timedelta 时间间隔
Enum str 一组字符串
PickleType 任何python对象 自动使用Pickle序列化
LargeBinary str 二进制blob

表5-3 最常用的SQLAlchemy列选项

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

四. 关系

       关系数据库使用关系把不同表中的行关联起来。关联关系包含:一对一/一对多(使用外键关联)/多对多(使用第三张表,关系表来实现)。如上述app.py定义的模型就实现了roles和users的一对多关系:

class Role(db.Model):
    """定义角色模型"""
    ...
    # 关联的另一端是哪个模型
    users = db.relationship('User', backref='role')


class User(db.Model):
    """定义用户模型"""
    ...
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
  • 添加到User模型的role_id列为外键,参数'roles.id'表明这列值是roles表中相应行的id值;
  • 添加到Role模型中的users属性,代表这个关系的面向对象视角,其users属性返回与角色相关联的用户组成的列表(即“多”那一端);
  • db.relationship()第一个参数表明这个关系的另一端是哪个模型(如果关联的模型类在后面定义,可以使用字符串的形式定义);
  • backref参数向User模型中添加一个role属性,来定义反向关系:通过User实例的这个属性可以获取对应的Role模型对象,而不再需要role_id外键获取。

表5-4 常用的SQLAlchemy关系选项

选项名 说明
backref 在关系的另一个模型中添加反向引用
uselist 设为False,表示不使用列表,使用标量值(一对一关系)
secondary 多对多关系中关联表的名称
order_by 关系中记录的排序方式
primaryjoin 指定2个模型间使用的联结条件,只在模棱两可的关系中指定
secondaryjoin SQLAlchemy无法自行决定时,指定多对多关系中的二级联结条件
lazy

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

  • select:首次访问时按需加载;
  • immediate:源对象加载后就加载;
  • joined:记载记录,但是用联结;
  • subquery:立即加载但是用子查询;
  • noload:永不加载;
  • dynamic:不加载记录但提供加载记录的查询。

 

你可能感兴趣的:(Flask)