Flask-Grundlegende Inhalte-Sechs

I、Flask数据关联模型SQLAlchemy

Flask-SQLAlchemy使用起来非常有趣,对于基本应用十分容易使用,并且对于大型项目易于扩展。有关完整的指南,请参见SQLAlchemyAPI文档。

常见情况下对于只有一个 Flask 应用,所有您需要做的事情就是创建 Flask 应用,选择加载配置接着创建 SQLAlchemy 对象时候把 Flask 应用传递给它作为参数。

一旦创建,这个对象就包含 sqlalchemysqlalchemy.orm 中的所有函数和助手。此外它还提供一个名为 Model的类,用于作为声明模型时的 delarative 基类

普通的 SQLAlchemy 不同之处:
1. SQLAlchemy 允许您访问下面的东西 :
·sqlalchemysqlalchemy.orm 下所有的函数和类
·一个叫做 session的预配置范围的会话(session)
·metadata 属性
·engine 属性
·SQLAlchemy.create_all()SQLAlchemy.drop_all(),根据模型用来创建以及删除表格的方法
· 一个 Model 基类,即是一个已配置的声明(declarative)的基础(base)
2. Model 声明基类行为类似一个常规的 Python 类,不过有个query属性,可以用来查询模型 (ModelBaseQuery)
3. 您必须提交会话,但是没有必要在每个请求后删除它(session),Flask-SQLAlchemy 会帮您完成删除操作。

\color{violet}{在了解以上问题后,这一章我们将用ORM的力量优化数据库操作。}

什么是ORM?
ORM是用来把对象模型表示的对象映射到基于SQL的关系模型数据库结构中去。简明点说,数据库中每一行就是一个对象。


II、相关的配置字段

在上一章内,我们在db_demo内应用课许多诸如app.config['SQLALCHEMY_DATABASE_URI'] = xxx的语句,这些语句为SQLAlchemy的配置方式

那么常见的配置选项有

选项 说明
SQLALCHEMY_DATABASE_URI 用于连接的数据库 URI 。例如:sqlite:////tmp/test.db 或 mysql://username:password@server/db
SQLALCHEMY_BINDS 一个映射 binds 到连接 URI 的字典。更多 binds 的信息见 用 Binds 操作多个数据库 。
SQLALCHEMY_ECHO 如果设置为 Ture , SQLAlchemy 会记录所有 发给 stderr 的语句,这对调试有用。
SQLALCHEMY_RECORD_QUERIES 可以用于显式地禁用或启用查询记录。查询记录 在调试或测试模式自动启用。更多信息见 get_debug_queries() 。
SQLALCHEMY_NATIVE_UNICODE 可以用于显式禁用原生 unicode 支持。当使用不合适的指定无编码的数据库默认值时,这对于 一些数据库适配器是必须的(比如 Ubuntu 上某些版本的 PostgreSQL )。
SQLALCHEMY_POOL_SIZE 数据库连接池的大小。默认是引擎默认值(通常 是 5 )
SQLALCHEMY_POOL_TIMEOUT 设定连接池的连接超时时间。默认是 10 。
SQLALCHEMY_POOL_RECYCLE 多少秒后自动回收连接。这对 MySQL 是必要的, 它默认移除闲置多于 8 小时的连接。注意如果 使用了 MySQL , Flask-SQLALchemy 自动设定这个值为 2 小时。

III、常见数据模型字段

类型名 python中类型 说明
Integer int 普通整数,一般是32位
SmallInteger int 取值范围小的整数,一般是16位
BigInteger int/long 不限制精度的整数
Float float 浮点数
Numeric decimal.Decimal 普通整数,一般是32位
String str 变长字符串
Text str 变长字符串,对较长或不限长度的字符串做了优化
Unicode unicode 变长Unicode字符串
UnicodeText unicode 变长Unicode字符串,对较长或不限长度的字符串做了优化
Boolean bool 布尔值
Date datetime.date 时间
Time datetime.datetime 日期和时间
LargeBinary str 二进制文件

IV、约束字段与表间关系

由于Flask-SQLAlchemy不自动设置表内的字段的约束与,因此需要在设计数据字段时自行添加

那么常见的约束字段有

选项名 说明
primary_key 如果为True,代表表的主键
unique 如果为True,代表这列不允许出现重复的值
index 如果为True,为这列创建索引,提高查询效率
nullable 如果为True,允许有空值,如果为False,不允许有空值
default 为这列定义默认值
autoincrement 自增

由于不自行设计id值(与Django的一定区别)Flask-SQLAlchemy并不涉及到表间关系的自动配置,因此需要了解表间关系联系字段

常见的表间关系字段有

选项名 说明
backref 在关系的另一模型中添加反向引用,用于设置外键名称,在1内查n的
primary join 明确指定两个模型之间使用的联结条件
uselist 如果为False,不使用列表,而使用标量值
order_by 指定关系中记录的排序方式
secondary 指定多对多关系中关系表的名字
secondary join 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
lazy 指定如何加载相关记录。

lazy的可选值有

属性 说明
select 首次访问时按需加载
immediate 源对象加载后就加载
joined 加载记录,但使用联结
subquery 立即加载,但使用子查询
noload 永不加载
dynamic 不加载记录,但提供加载记录的查询

V、查询执行器

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

VI、过滤器

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


filter_by用于查询简单的列名,不支持比较运算符。
比filter_by的功能更强大,支持比较运算符,支持or_、in_等语法。


VII、一个简单的建表实例

我们基于上一章中的db_demo.py的内容展开,在每一个修改的实例内增加一个__repr__方法,简单介绍一下__repr__:当我们需要对一个函数中传入某个参数后的状态需要打包打印,或者显示在屏幕上时我们可以在这个函数内部定义一个__repr__函数,可以通过这个函数,对你想要打印的内容进行设置。

修改db_demo.py

class Role(db.Model):
    # 定义表名
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    db.relationship('User', backref='role')

    def __repr__(self):
        return 'Role:{}'.format(self.name)


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

    def __repr__(self):
        return 'User:{}'.format(self.name)


VIII、一些查询的联系

在此前,我们修改db_demo内的main,以用来插入一些数据,当然,这种方式并非日后的常用方法,这里只作为一种简单的填充

if __name__ == '__main__':
    # 删除表
    db.drop_all()
    # 创建表
    db.create_all()
    ro1 = Role(name='admin')
    ro2 = Role(name='user')
    db.session.add_all([ro1, ro2])
    db.session.commit()
    us1 = User(name='wang', email='wang@163.com', password='123456', role_id=ro1.id)
    us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=ro2.id)
    us3 = User(name='chen', email='chen@126.com', password='987654', role_id=ro2.id)
    us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=ro1.id)
    us5 = User(name='tang', email='tang@neuedu.com', password='158104', role_id=ro2.id)
    us6 = User(name='wu', email='wu@gmail.com', password='5623514', role_id=ro2.id)
    us7 = User(name='qian', email='qian@gmail.com', password='1543567', role_id=ro1.id)
    us8 = User(name='liu', email='liu@neuedu.com', password='867322', role_id=ro1.id)
    us9 = User(name='li', email='li@163.com', password='4526342', role_id=ro2.id)
    us10 = User(name='sun', email='sun@163.com', password='235523', role_id=ro2.id)
    db.session.add_all([us1, us2, us3, us4, us5, us6, us7, us8, us9, us10])
    db.session.commit()
    db.session.add_all([us1, us2])
    db.session.commit()
    app.run(port=5005,debug=True)

1、返回名字等于wang 的所有人

    User.query.filter_by(name='wang').all()

2、返回查询的第一个对象

    User.query.first()

3、返回所有查询对象

    User.query.all()

4、返回名字结尾字符为g的所有数据

    User.query.filter(User.name.endswith("g")).all()
    User.query.filter(User.name.startswith("w")).all()
    User.query.filter(User.name.contains("n")).all()
    User.query.filter(User.name.like("%n%g")).all()

5、返回user中id = 1的数据

    User.query.get(1)

6、返回名字不等于wang的所有数据

    User.query.filter(not_(User.name == "wang")).all()
    User.query.filter(User.name != "wang").all()

7、返回名字不等于 wang 且 邮箱 以 163.com结尾的所有

    User.query.filter(or_(User.name != 'wang',User.email.endswith('163.com') )).all()

8、查询名字和邮箱都以 li 开头的所有数据

    User.query.filter(User.name.startswith("li"), User.email.startswith("li")).all()
    User.query.filter(and_(User.name.startswith("li"), User.email.startswith("li"))).all()

9、查询password是 123456 或者 emailneuedu.com 结尾的所有数据

    User.query.filter(or_(User.password == '123456', User.email.endswith('neuedu.com'))).all()

10、查询id为 [1, 3, 5, 7, 9] 的用户列表

    User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()

11、 查询name为liu的角色数据

     User.query.filter(User.name == 'liu').all()

12、查询所有用户数据,并以邮箱排序

    User.query.order_by(User.email.desc()).all()

13、每页3个,查询第2页的数据

    pn = User.query.paginate(2, 3)
    pn.items # 获取该页内容
    pn.page # 获取该页页码
    pn.pages # 获取总页数

14、定义模型,并显示作者名和书名
作者Author(),表名 author,属性有:id,name,au_book(外键)
书名Book(),表名 books ,属性有:id,name,au_book

class Author(db.Model):
    __tablename__ = 'author'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    au_book = db.Column(db.Integer, db.ForeignKey('book.id'))

    def __repr__(self):
        return 'Author:{}'.format(self.name)


class Book(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    au_book = db.relationship('Book', backref='book')

    def __repr__(self):
        return 'Book:{}'.format(self.name)

IX、增删改的操作

Flask-SQLAlchemy的增删改操作可以理解为是通过与数据库建立一个小型会话的方式进行的,下面介绍一下这些基于db = SQLAlchemy(app)的操作

操作 说明
create_all() 建表操作,db.create_all()
drop_all() 删除表操作,db.drop_all()
add_all() 插入操作,db.seesion.add_all([]),插入可选择使用list进行批量插入
commit() 提交操作,db.session.commit(),提交其语句以上的所有更改数据库内容的操作
delete() 删除操作,db.session.delete(),删除一条数据

更新操作只需要选择需要更新的对象,修改其属性值然后提交即可。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。