Flutter + FastAPI 30天速成计划自用并实践-第4天
·
Day 4 详细学习计划:完整 CRUD 操作实现
学习目标
- 理解 RESTful API 设计原则
- 实现完整的增删改查接口
- 学习 FastAPI 的依赖注入系统
- 掌握数据库会话(Session)管理
知识点详解
1. RESTful API 设计原则
核心概念:
- 使用标准 HTTP 方法:GET(查询)、POST(创建)、PUT(更新)、DELETE(删除)
- URI 表示资源:/articles 表示文章集合,/articles/1 表示特定文章
- 无状态:每次请求应包含所有必要信息
常见的 HTTP 状态码:
- 200 OK:请求成功
- 201 Created:创建成功
- 400 Bad Request:客户端请求错误
- 404 Not Found:资源不存在
- 500 Internal Server Error:服务器内部错误
2. FastAPI 依赖注入系统
概念:
- 自动处理依赖关系
- 减少重复代码
- 提高代码可测试性和可维护性
常用场景:
- 数据库会话管理
- 认证和授权
- 配置参数传递
3. 数据库会话管理
重要性:
- 管理与数据库的连接
- 控制事务边界
- 确保数据一致性
练习代码
day4 目录中有以下文件:
database.py - 定义了数据库模型和连接配置
schemas.py - 定义了各种数据模型(基础模型、创建、更新、读取模型)
main.py - FastAPI 主应用程序,包含了所有 REST API 接口
第四天的内容.md - 学习笔记
database.py
from sqlmodel import SQLModel, create_engine, Field, Session
from typing import Optional
from datetime import datetime
# 数据库文件Url
DATABASE_URL = "sqlite:///./articles.db"
# 创建数据库引擎,echo=True表示打印SQL语句
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 #yield作用是返回一个迭代器,迭代器中的数据是yield后面的数据
schemas.py
from sqlmodel import SQLModel, Field
from typing import Optional
from datetime import datetime
# 数据库模型和响应模型共用的基础模型
class ArticleBase(SQLModel):
title: str
content: str
author: Optional[str] = None
published: bool = False
# 数据库模型
class Article(ArticleBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
created_at: Optional[datetime] = None
# 创建文章时使用的模型
class ArticleCreate(ArticleBase):
pass
# 更新文章时使用的模型
class ArticleUpdate(ArticleBase):
title: Optional[str] = None
content: Optional[str] = None
# 数据库返回的文章模型
class ArticleRead(ArticleBase):
id: int
created_at: Optional[datetime] = None
main.py
from fastapi import FastAPI, Depends, HTTPException, status
from sqlmodel import Session, select
from typing import List
from database import create_db_and_tables, get_session
from schemas import Article, ArticleCreate, ArticleUpdate, ArticleRead
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
# 应用启动时创建数据库表
create_db_and_tables()
yield
# 应用关闭时可以执行清理工作
app = FastAPI(title="Tutorial Site API", version="0.1.0", lifespan=lifespan)
# 创建文章接口
@app.post("/articles/", response_model=ArticleRead, status_code=status.HTTP_201_CREATED)
def create_article(*,
article: ArticleCreate,
session: Session = Depends(get_session)):
db_article = Article.from_orm(article)
session.add(db_article)
session.commit()
session.refresh(db_article)
return db_article
# 获取所有文章接口
@app.get("/articles/", response_model=List[ArticleRead])
def read_articles(*, session: Session = Depends(get_session)):
articles = session.exec(select(Article)).all()
return articles
# 根据ID获取单个文章接口
@app.get("/articles/{article_id}", response_model=ArticleRead)
def read_article(*, article_id: int, session: Session = Depends(get_session)):
article = session.get(Article, article_id)
if not article:
raise HTTPException(status_code=404, detail="Article not found")
return article
# 更新文章接口
@app.put("/articles/{article_id}", response_model=ArticleRead)
def update_article(*,
article_id: int,
article_update: ArticleUpdate,
session: Session = Depends(get_session)):
article = session.get(Article, article_id)
if not article:
raise HTTPException(status_code=404, detail="Article not found")
# 只更新提供了的字段
article_data = article_update.dict(exclude_unset=True)
for key, value in article_data.items():
setattr(article, key, value)
session.add(article)
session.commit()
session.refresh(article)
return article
# 删除文章接口
@app.delete("/articles/{article_id}")
def delete_article(*,
article_id: int,
session: Session = Depends(get_session)):
article = session.get(Article, article_id)
if not article:
raise HTTPException(status_code=404, detail="Article not found")
session.delete(article)
session.commit()
return {"ok": True}
# 根目录欢迎信息
@app.get("/")
def read_root():
return {"message": "Welcome to the tutorial site API!"}
Day3 vs Day4 对比
Day3 的结构
在 day3 中,你只有一个 database.py 文件,其中包含了 Article 模型的定义。这个模型同时承担了两个职责:
- 作为数据库表结构定义(通过
table=True) - 作为 API 请求和响应的数据验证模型
Day4 的结构
在 day4 中,你引入了 schemas.py 来专门处理数据模型,这种做法有以下几个重要变化和好处:
主要变化和好处
1. 关注点分离 (Separation of Concerns)
- Day3: 一个模型同时处理数据库操作和 API 数据验证
- Day4: 不同用途使用不同模型,各司其职
2. 更精确的控制
在 schemas.py 中,你定义了多个专用模型:
ArticleBase: 基础字段定义ArticleCreate: 创建文章时使用的模型ArticleUpdate: 更新文章时使用的模型ArticleRead: 返回给客户端的模型
3. 更好的 API 设计
- Day3: 创建文章时必须提供所有字段,包括自动生成的
id和created_at - Day4:
ArticleCreate只包含必要的字段,不需要提供id和created_at
4. 更灵活的数据验证
- 更新操作使用
ArticleUpdate,所有字段都是可选的(通过Optional),符合 PATCH 操作的语义 - 读取操作使用
ArticleRead,确保返回给客户端的数据结构是明确定义的
5. 增强的安全性和数据完整性
- 防止客户端意外或恶意地设置不应该由他们控制的字段(如
id和created_at) - 明确区分哪些字段在创建时是必需的,哪些是可选的
实际效果示例
在 Day3 中
API 文档会显示创建文章需要提供所有字段,包括 id 和 created_at:
{
"id": 0,
"title": "string",
"content": "string",
"author": "string",
"published": true,
"created_at": "2025-12-01T00:32:45.123Z"
}
在 Day4 中
API 文档只显示真正需要的字段:
{
"title": "string",
"content": "string",
"author": "string",
"published": true
}
这就是引入 schemas.py 的主要好处:
更清晰的代码结构
更好的 API 设计
更强的数据完整性和安全性
今天学习2个多小时,已经快1点了,今天的主要内容就是增加了个schemas.py就是有点好处,不过我感触不深,学的越来越浅了,烂
更多推荐



所有评论(0)