第四章 数据库入门 —— 数据存到哪里?
本章目标:理解数据库的作用,学会用 SQLModel 定义表结构和连接数据库。
4.1 为什么需要数据库
上一章的代码中,我们用一个 Python 列表 fake_db 来存数据。但它有一个致命问题:
服务一关,数据全没。
因为列表存在内存里,程序退出后内存被释放,数据自然消失。
数据库的作用就是:把数据存到磁盘上(硬盘/SSD),程序关了数据还在,下次启动还能读出来。
生活类比
| 方式 | 类比 | 特点 |
|---|---|---|
| 变量/列表 | 黑板上写字 | 擦了就没了 |
| 数据库 | 笔记本上写字 | 合上本子字还在 |
4.2 选择 SQLite + SQLModel
为什么选 SQLite
市面上有很多数据库:MySQL、PostgreSQL、MongoDB……
但对于学习来说,SQLite 是最佳选择:
| 特点 | 说明 |
|---|---|
| 无需安装 | Python 自带 SQLite 支持 |
| 无需启动服务 | 不像 MySQL 需要启动一个数据库服务器 |
| 一个文件 | 整个数据库就是一个 .db 文件 |
| 足够用 | 对于学习和小项目完全够用 |
为什么选 SQLModel
操作数据库传统方式是写 SQL 语句:
INSERT INTO todo (title, done) VALUES ('买牛奶', 0);
SELECT * FROM todo;
SQLModel 让你用 Python 类 来代替 SQL 语句,对 Python 开发者更友好:
# 定义表
class Todo(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
title: str
done: bool = False
# 新增一条数据
todo = Todo(title="买牛奶")
session.add(todo)
session.commit()
不用写 SQL,用 Python 就能操作数据库,这就是 SQLModel 的价值。
4.3 定义数据模型(建表)
什么是”表”
数据库里的”表”就像 Excel 的一个 sheet:
| id | title | done |
|---|---|---|
| 1 | 买牛奶 | false |
| 2 | 写作业 | true |
| 3 | 跑步 | false |
- 每一行是一条数据(一个待办事项)
- 每一列是一个字段(id、title、done)
用 Python 类定义表
创建 models.py:
from sqlmodel import SQLModel, Field
class Todo(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
title: str
done: bool = False
逐行解释:
| 代码 | 含义 |
|---|---|
class Todo(SQLModel, table=True) | 定义一个名为 todo 的数据库表 |
id: int | None = Field(default=None, primary_key=True) | id 字段,整数,主键,由数据库自动生成 |
title: str | title 字段,字符串,必填 |
done: bool = False | done 字段,布尔值,默认为 False |
关键概念:
table=True:告诉 SQLModel 这个类对应一张数据库表(不加就只是普通的数据模型)- 主键(primary_key):每条数据的唯一标识,不能重复。设为
None表示新增时由数据库自动分配 - 默认值:
done: bool = False表示如果不传 done,默认为 False
顺便定义一个”创建用”的模型
我们还需要一个不带 id 的模型,用于接收前端的创建请求:
class TodoCreate(SQLModel):
title: str
done: bool = False
注意这里没有 table=True,因为它不对应数据库表,只是用来定义”创建时需要传什么参数”。
完整 models.py
from sqlmodel import SQLModel, Field
class TodoCreate(SQLModel):
"""创建 Todo 时的请求体模型"""
title: str
done: bool = False
class TodoUpdate(SQLModel):
"""更新 Todo 时的请求体模型"""
title: str | None = None
done: bool | None = None
class Todo(SQLModel, table=True):
"""Todo 数据库表"""
id: int | None = Field(default=None, primary_key=True)
title: str
done: bool = False
我们定义了三个模型:
Todo→ 数据库表,有 idTodoCreate→ 新增时使用,不需要传 idTodoUpdate→ 修改时使用,所有字段都可选(只传要改的)
4.4 连接数据库
创建 database.py
from sqlmodel import SQLModel, Session, create_engine
DATABASE_URL = "sqlite:///database.db"
engine = create_engine(DATABASE_URL, echo=True)
def create_db_and_tables():
SQLModel.metadata.create_all(engine)
def get_session():
with Session(engine) as session:
yield session
逐行解释:
| 代码 | 含义 |
|---|---|
DATABASE_URL = "sqlite:///database.db" | 数据库地址,使用 SQLite,文件名为 database.db |
engine = create_engine(...) | 创建数据库引擎(连接池),是程序和数据库之间的桥梁 |
echo=True | 开发模式,会在终端打印执行的 SQL 语句(方便学习) |
create_db_and_tables() | 根据我们定义的模型,自动创建数据库和表 |
get_session() | 获取一个数据库会话(Session),每次操作数据库都需要一个会话 |
什么是 Session(会话)
你可以把 Session 理解为:你和数据库之间的一次对话。
你: "帮我存一条数据" → session.add(todo)
你: "确认保存" → session.commit()
你: "帮我查个数据" → session.exec(select(Todo))
对话结束后(with 语句结束),Session 自动关闭。
在 main.py 中使用
更新 main.py,让服务启动时自动创建数据库:
from contextlib import asynccontextmanager
from fastapi import FastAPI
from database import create_db_and_tables
@asynccontextmanager
async def lifespan(app: FastAPI):
create_db_and_tables()
yield
app = FastAPI(lifespan=lifespan)
@app.get("/")
def index():
return {"message": "Todo 后台服务已启动"}
lifespan 的作用:在服务启动时执行初始化操作(创建数据库表)。yield 之前的代码在启动时运行,之后的代码在关闭时运行。
启动后观察
运行 uvicorn main:app --reload,你会在终端看到类似输出:
CREATE TABLE todo (
id INTEGER NOT NULL,
title VARCHAR NOT NULL,
done BOOLEAN NOT NULL,
PRIMARY KEY (id)
)
同时项目目录下会多出一个 database.db 文件——这就是你的数据库!
你可以用 DB Browser for SQLite 打开这个文件,看到一张空的 todo 表。
本章小结
| 概念 | 说明 |
|---|---|
| 数据库 | 把数据持久化存储到磁盘的工具 |
| SQLite | 最简单的数据库,一个文件就是一个数据库 |
| SQLModel | 用 Python 类定义数据库表,不用写 SQL |
| 模型(Model) | 一个 Python 类,对应数据库中的一张表 |
| 引擎(Engine) | 程序和数据库之间的连接桥梁 |
| 会话(Session) | 一次数据库操作的上下文,增删改查都通过它 |
当前项目文件:
todo_backend/
├── main.py ← 入口,目前只有一个首页接口
├── models.py ← 定义了 Todo、TodoCreate、TodoUpdate
├── database.py ← 数据库连接配置
├── requirements.txt
└── database.db ← 自动生成的数据库文件
下一章是整个教程的核心——增删改查(CRUD),我们将真正用 FastAPI + SQLModel 实现对数据库的操作。