第5章数据库,实体关系图,ER图

文章目录

  • 摘要
  • 5.1 SQL数据库
  • 5.3 使用SQL还是NoSQL
  • 5.4 Python数据库框架
  • 5.5 使用Flask-SQLAlchemy管理数据库
    • [Flask-SQLAlchemy 的数据库连接 URL(Database URL)格式](#Flask-SQLAlchemy 的数据库连接 URL(Database URL)格式)
    • [SQLALCHEMY_DATABASE_URI,告诉 Flask-SQLAlchemy 要连接哪个数据库](#SQLALCHEMY_DATABASE_URI,告诉 Flask-SQLAlchemy 要连接哪个数据库)
    • SQLALCHEMY_TRACK_MODIFICATIONS
    • 配置示例
      • [db = SQLAlchemy(app)。把 Flask 应用和数据库系统绑定起来,并创建一个统一操作数据库的核心对象](#db = SQLAlchemy(app)。把 Flask 应用和数据库系统绑定起来,并创建一个统一操作数据库的核心对象)
        • [为什么说"db 表示应用使用的数据库"?](#为什么说“db 表示应用使用的数据库”?)
        • [SQLAlchemy(app) 只是"准备好连接数据库",真正的数据库连接通常发生在第一次实际数据库操作时。](#SQLAlchemy(app) 只是“准备好连接数据库”,真正的数据库连接通常发生在第一次实际数据库操作时。)
          • [SQLite 是个特殊情况。没有网络连接。在第一次访问时打开文件。如果文件不存在会创建文件](#SQLite 是个特殊情况。没有网络连接。在第一次访问时打开文件。如果文件不存在会创建文件)
      • [app.config 是 Flask 应用的"配置字典"。应用的全局设置中心。扩展通过它读取自己的配置](#app.config 是 Flask 应用的“配置字典”。应用的全局设置中心。扩展通过它读取自己的配置)
      • db.init_app(app),先创建,再绑定
      • [app.config.from_object(xx)加载对应配置类里的设置到 app.config字段](#app.config.from_object(xx)加载对应配置类里的设置到 app.config字段)
    • [为什么 Flask 必须有 application context 才能访问数据库?](#为什么 Flask 必须有 application context 才能访问数据库?)
      • [application context 是什么?每当有请求进入,自动创建应用的上下文](#application context 是什么?每当有请求进入,自动创建应用的上下文)
  • 5.6 定义模型
    • [模型 = 用 Python 类表示数据库表。模型就是用面向对象方式操作数据库表。在 ORM 里:一个类 → 一张表。类的属性 → 表的列。类的实例 → 表中的一行数据](#模型 = 用 Python 类表示数据库表。模型就是用面向对象方式操作数据库表。在 ORM 里:一个类 → 一张表。类的属性 → 表的列。类的实例 → 表中的一行数据)
      • [db.Model 是什么?所有模型类必须继承的基类](#db.Model 是什么?所有模型类必须继承的基类)
  • 5.7 关系
    • [relationship()是用来在 Python 里建立两个模型之间的联系](#relationship()是用来在 Python 里建立两个模型之间的联系)
      • relationship参数
        • 第一个参数是要关联的"目标模型"
        • [back_populates 是:手动建立"双方都知道对方"的关系。](#back_populates 是:手动建立“双方都知道对方”的关系。)
          • [back_populates 写的是:对方模型里 relationship 对应的变量名](#back_populates 写的是:对方模型里 relationship 对应的变量名)
        • [backref ------ 自动创建"反向访问",在对方的模型里自动生成一个属性](#backref —— 自动创建“反向访问”,在对方的模型里自动生成一个属性)
          • [如果你在父表里写了 backref,子表就不需要再手动写那个属性,ORM 会帮你自动创建](#如果你在父表里写了 backref,子表就不需要再手动写那个属性,ORM 会帮你自动创建)
        • [primaryjoin ------ 指定怎么连接](#primaryjoin —— 指定怎么连接)
        • [lazy ------ 决定访问关系属性时数据库什么时候发 SQL](#lazy —— 决定访问关系属性时数据库什么时候发 SQL)
        • [uselist ------ 控制是不是列表](#uselist —— 控制是不是列表)
        • [order_by ------ 排序](#order_by —— 排序)
        • [secondary ------ 告诉 ORM:两张表之间要"通过第三张表连接"](#secondary —— 告诉 ORM:两张表之间要“通过第三张表连接”)
        • [secondaryjoin ------ 多对多复杂连接](#secondaryjoin —— 多对多复杂连接)
        • [primaryjoin / secondaryjoin](#primaryjoin / secondaryjoin)
      • [靠外键建立联系。它根据 ForeignKey 自动推断 JOIN 条件](#靠外键建立联系。它根据 ForeignKey 自动推断 JOIN 条件)
      • [relationship 返回的到底是什么?属性描述器](#relationship 返回的到底是什么?属性描述器)
      • 返回值具体是什么?取决于关系类型
    • 把外键和db.relationship()都放在"多"这一侧
  • 连接数据库的工具:DBeaver (Community Edition)
  • 5.8 数据库操作
    • [5.8.1 创建表 db.create_all()](#5.8.1 创建表 db.create_all())
    • 5.8.2 插入行
      • 数据库Session(会话)。也称事务
      • [为什么必须要有 session?](#为什么必须要有 session?)
      • [为什么是 db.session?当前 Flask 应用绑定的数据库db,操作的会话](#为什么是 db.session?当前 Flask 应用绑定的数据库db,操作的会话)
        • [session 是绑定在 SQLAlchemy 实例上的](#session 是绑定在 SQLAlchemy 实例上的)
        • [Flask-SQLAlchemy session 的绑定规则.不同代码块的应用上下文,对应的session不一样](#Flask-SQLAlchemy session 的绑定规则.不同代码块的应用上下文,对应的session不一样)
        • [db.session = "当前请求专属的数据库会话"。只要不在请求里,用 db.session 就必须加 app.app_context()](#db.session = “当前请求专属的数据库会话”。只要不在请求里,用 db.session 就必须加 app.app_context())
        • [db.session 依赖 Flask 的"应用上下文(app context)](#db.session 依赖 Flask 的“应用上下文(app context))
          • 那什么时候"自动有上下文"?
          • [没有上下文需要手动加上下文。只要不在请求里,用 db.session 就必须加 app.app_context()](#没有上下文需要手动加上下文。只要不在请求里,用 db.session 就必须加 app.app_context())
            • [为什么"请求里"就可以用 db.session?处理请求flask会自动创建上下文](#为什么“请求里”就可以用 db.session?处理请求flask会自动创建上下文)
            • ["请求来了之后,Flask 内部到底发生了什么?"](#“请求来了之后,Flask 内部到底发生了什么?”)
        • [Flask 有两种上下文:请求时自动创建(最常见).你可以手动创建(app.app_context())](#Flask 有两种上下文:请求时自动创建(最常见).你可以手动创建(app.app_context()))
      • [还有别的 session 吗?](#还有别的 session 吗?)
        • [引擎:是 SQLAlchemy 在数据库驱动之上的一层封装](#引擎:是 SQLAlchemy 在数据库驱动之上的一层封装)
        • [Flask-SQLAlchemy 已经自动创建了 engine 和 db.session,如果我想自己手动创建一个新的 session,但还是用这个 engine,该怎么操作?](#Flask-SQLAlchemy 已经自动创建了 engine 和 db.session,如果我想自己手动创建一个新的 session,但还是用这个 engine,该怎么操作?)
      • [如果不是浏览器的请求,就不用db.session? 比如有定时任务,需要操作数据库,用什么session?](#如果不是浏览器的请求,就不用db.session? 比如有定时任务,需要操作数据库,用什么session?)
        • [使用 db.session](#使用 db.session)
        • [手动创建 session](#手动创建 session)
      • 手动关闭session
    • 事务=一组必须"要么全部成功,要么全部失败"的数据库操作。session是事务的容器
      • [事务失败后 必须手动 db.session.rollback()](#事务失败后 必须手动 db.session.rollback())
    • [user_john = User(username='john', role=admin_role)](#user_john = User(username='john', role=admin_role))
    • [在 flask shell 里,其实已经自动帮你推入了 app context。所以你才能直接用:db.session.add(admin_role)而不报错。](#在 flask shell 里,其实已经自动帮你推入了 app context。所以你才能直接用:db.session.add(admin_role)而不报错。)
    • add_all,参数是一个"可迭代对象"(iterable)
  • 5.8.5 查询行
  • [5.10 集成Python shell。shell_context_processor 是给 Flask shell 预加载变量用的](#5.10 集成Python shell。shell_context_processor 是给 Flask shell 预加载变量用的)
  • 5.11 使用Flask-Migrate实现数据库迁移
    • 5.11.1 创建迁移仓库
      • [migrate = Migrate(app, db)把 Flask 应用 和 SQLAlchemy 数据库 绑定到 Flask-Migrate。](#migrate = Migrate(app, db)把 Flask 应用 和 SQLAlchemy 数据库 绑定到 Flask-Migrate。)
      • [flask db init 初始化 Alembic(迁移引擎)](#flask db init 初始化 Alembic(迁移引擎))
      • 正常迁移流程
    • 5.11.2 创建迁移脚本
      • [Alembic 的 版本管理和迁移逻辑](#Alembic 的 版本管理和迁移逻辑)
      • [flask db migrate -m "initial migration"](#flask db migrate -m "initial migration")
    • 5.11.3 更新数据库
      • [使用 flask db stamp 标记数据库](#使用 flask db stamp 标记数据库)

摘要

SQL 数据库(关系型数据库)

NoSQL 数据库


什么是反规范化(Denormalization)?



5.1 SQL数据库

实体关系图,ER图

5.3 使用SQL还是NoSQL

ACID的范式






5.4 Python数据库框架

对象关系映射器(ORM)。把面向对象的代码,自动转换为数据库操作


数据库驱动





数据类型转换就是把程序里的数据类型,转换成数据库能理解的格式,或者把数据库返回的数据转换回程序的数据类型










性能

可移植性

数据库管理系统:创建、管理和操作数据库的完整软件系统



数据库引擎(Database Engine):数据库系统中负责数据存储和查询执行的核心底层组件

数据库引擎(Storage Engine)是数据库管理系统(DBMS)里的一个组件,它负责实际存储和读取数据。








数据库管理系统 vs 数据库 vs 数据库引擎


Python对象 → ORM → 驱动 → DBMS → 存储引擎 → 磁盘文件


在 Flask 项目中如何选择数据库框架

Flask-SQLAlchemy 本质上是对 SQLAlchemy 的封装




SQLAlchemy 实际连接的是什么?

5.5 使用Flask-SQLAlchemy管理数据库

Flask-SQLAlchemy 的数据库连接 URL(Database URL)格式

什么是数据库 URL?一种用字符串描述"如何连接数据库"的标准格式

通用格式,数据库类型://用户名:密码@主机名/数据库名

mysql,postgresql,sqlite示例




SQLAlchemy 通常还会指定驱动。数据库类型+驱动://用户名:密码@主机名/数据库名

SQLALCHEMY_DATABASE_URI,告诉 Flask-SQLAlchemy 要连接哪个数据库

SQLALCHEMY_TRACK_MODIFICATIONS

配置示例

db = SQLAlchemy(app)。把 Flask 应用和数据库系统绑定起来,并创建一个统一操作数据库的核心对象

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

详情见本章引擎章节




为什么说"db 表示应用使用的数据库"?
SQLAlchemy(app) 只是"准备好连接数据库",真正的数据库连接通常发生在第一次实际数据库操作时。
SQLite 是个特殊情况。没有网络连接。在第一次访问时打开文件。如果文件不存在会创建文件

app.config 是 Flask 应用的"配置字典"。应用的全局设置中心。扩展通过它读取自己的配置







db.init_app(app),先创建,再绑定





p 复制代码
def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config_map[config_name])
    db.init_app(app)
    return app









app.config.from_object(xx)加载对应配置类里的设置到 app.config字段






为什么 Flask 必须有 application context 才能访问数据库?


application context 是什么?每当有请求进入,自动创建应用的上下文



5.6 定义模型

模型 = 用 Python 类表示数据库表。模型就是用面向对象方式操作数据库表。在 ORM 里:一个类 → 一张表。类的属性 → 表的列。类的实例 → 表中的一行数据





db.Model 是什么?所有模型类必须继承的基类




5.7 关系

relationship()是用来在 Python 里建立两个模型之间的联系


relationship参数

第一个参数是要关联的"目标模型"




back_populates 是:手动建立"双方都知道对方"的关系。


backref也有这个同步的功能







back_populates 写的是:对方模型里 relationship 对应的变量名


backref ------ 自动创建"反向访问",在对方的模型里自动生成一个属性


如果你在父表里写了 backref,子表就不需要再手动写那个属性,ORM 会帮你自动创建





primaryjoin ------ 指定怎么连接
lazy ------ 决定访问关系属性时数据库什么时候发 SQL


含义 小白理解
select 默认,首次访问时查询 惰性加载:你不访问 users,不发 SQL;访问时发一次 SQL
joined 使用 JOIN 一次查出 查询 Role 时,顺便 join 查出所有 User
subquery 使用子查询 查询 Role 后再发子查询查 users,一次加载但分两步
immediate 主对象加载完就加载 一创建 Role,就查 users
noload 永远不加载 不管访问不访问,永远不查用户
dynamic 不返回列表,而返回查询对象 不加载 users,只返回 query,可以继续 filter、order_by









uselist ------ 控制是不是列表






order_by ------ 排序
secondary ------ 告诉 ORM:两张表之间要"通过第三张表连接"


















secondaryjoin ------ 多对多复杂连接









primaryjoin / secondaryjoin







primaryjoin 是指 第一段连接,不一定是怎么和中间表连,只有多对多才是怎么和第一张表连,一对多就是怎么 和对方连。secondaryjoin = 第二段连接(只有多对多才有)












靠外键建立联系。它根据 ForeignKey 自动推断 JOIN 条件




relationship 返回的到底是什么?属性描述器


返回值具体是什么?取决于关系类型

父对象的 relationship 属性是列表,列表里是单个子对象

子对象的 relationship 属性是单个父对象



怎么知道是一对多还是多对一的关系?看外键在哪一边

把外键和db.relationship()都放在"多"这一侧




连接数据库的工具:DBeaver (Community Edition)

下载安装

官网下载地址

5.8 数据库操作

5.8.1 创建表 db.create_all()

db.create_all()不会重新创建或者更新相应的表









5.8.2 插入行

数据库Session(会话)。也称事务





为什么必须要有 session?





为什么是 db.session?当前 Flask 应用绑定的数据库db,操作的会话


session 是绑定在 SQLAlchemy 实例上的
Flask-SQLAlchemy session 的绑定规则.不同代码块的应用上下文,对应的session不一样




db.session = "当前请求专属的数据库会话"。只要不在请求里,用 db.session 就必须加 app.app_context()

一个请求 = 一个 session

浏览器请求 → Flask → db.session → 数据库 请求结束:

👉 session 自动清理





db.session 依赖 Flask 的"应用上下文(app context)


那什么时候"自动有上下文"?
没有上下文需要手动加上下文。只要不在请求里,用 db.session 就必须加 app.app_context()







为什么"请求里"就可以用 db.session?处理请求flask会自动创建上下文
"请求来了之后,Flask 内部到底发生了什么?"






Flask 有两种上下文:请求时自动创建(最常见).你可以手动创建(app.app_context())



为什么要有app.app_context()?给flask提供在哪个应用里操作,这样session等可以工作






还有别的 session 吗?


引擎:是 SQLAlchemy 在数据库驱动之上的一层封装







Flask-SQLAlchemy 已经自动创建了 engine 和 db.session,如果我想自己手动创建一个新的 session,但还是用这个 engine,该怎么操作?




如果不是浏览器的请求,就不用db.session? 比如有定时任务,需要操作数据库,用什么session?

Web 请求

Flask 自动:

创建 context → 提供 db.session → 自动销毁

⚙️ 定时 任务

你自己:

创建 context → 使用 db.session → 手动控制

使用 db.session









手动创建 session
p 复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import sessionmaker

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.sqlite'
db = SQLAlchemy(app)

with app.app_context():
    engine = db.get_engine()
    Session = sessionmaker(bind=engine)

def celery_task():
    session = Session()
    try:
        user = User(name="Alice")
        session.add(user)
        session.commit()
    except Exception:
        session.rollback()
        raise
    finally:
        session.close()

手动关闭session






事务=一组必须"要么全部成功,要么全部失败"的数据库操作。session是事务的容器




事务失败后 必须手动 db.session.rollback()








user_john = User(username='john', role=admin_role)






在 flask shell 里,其实已经自动帮你推入了 app context。所以你才能直接用:db.session.add(admin_role)而不报错。




add_all,参数是一个"可迭代对象"(iterable)



5.8.5 查询行

filter_by(...)






若想查看SQLAlchemy为查询生成的原生SQL查询语句,只需把query对象转换成字符串












filter()


filter_by()


limit(n)

offset(n)





order_by()

group_by()















真正"执行查询"并返回结果的方法


all

first

first_or_404

get

get_or_404

count

paginate














5.10 集成Python shell。shell_context_processor 是给 Flask shell 预加载变量用的









5.11 使用Flask-Migrate实现数据库迁移

5.11.1 创建迁移仓库

migrate = Migrate(app, db)把 Flask 应用 和 SQLAlchemy 数据库 绑定到 Flask-Migrate。

什么是数据库迁移?


flask db init 初始化 Alembic(迁移引擎)


正常迁移流程







5.11.2 创建迁移脚本












Alembic 的 版本管理和迁移逻辑












flask db migrate -m "initial migration"


5.11.3 更新数据库

使用 flask db stamp 标记数据库


相关推荐
锥栗2 小时前
【其他】基于Trae的大模型智能应用开发
android·java·数据库
qq_353737542 小时前
安全跳转页(用于网站内链,优化SEO)—炫酷特效黑客风格版
数据库·安全
yangyanping201082 小时前
微服务设计之带过期时间的积分系统
数据库
I'mAlex3 小时前
金仓数据库平替MongoDB实操解析:多模融合赋能企业文档数据管理国产化升级
数据库·mongodb·kingbasees·金仓数据库
Pocker_Spades_A3 小时前
MongoDB 远程连不上?用cpolar告别局域网束缚,跨网访问就这么简单
数据库·mongodb
鸽芷咕3 小时前
从底层到实战,金仓多模数据库 MongoDB 兼容的技术实力到底有多强?
数据库·mongodb·金仓数据库
王家视频教程图书馆3 小时前
开源api
数据库
康小庄3 小时前
Java阻塞队列——用法及常用场景
java·开发语言·数据库·spring boot·spring·jetty
m0_528749004 小时前
MySQL CAPI核心操作全解析
数据库·mysql