blog搭建笔记day2

将后端的模拟数据替换为真实的数据库。#

我们一步一步来创建这些文件。

第一步:创建数据库连接 (database.py)
这个文件负责设置与数据库的连接,并管理数据库会话。

在 backend 目录下创建一个新文件 database.py,并填入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# backend/database.py

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 数据库URL,"sqlite:///./blog.db" 表示在当前目录下创建一个名为 blog.db 的SQLite数据库文件
SQLALCHEMY_DATABASE_URL = "sqlite:///./blog.db"

# 创建SQLAlchemy引擎
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} # check_same_thread只在SQLite需要
)

# 创建一个数据库会话类
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建一个Base类,我们之后创建的数据库模型将继承这个类
Base = declarative_base()

第二步:创建数据库模型 (models.py)
这个文件定义了你的数据在数据库中是如何存储的。每个类都代表一张数据表。

在 backend 目录下创建 models.py 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
# backend/models.py

from sqlalchemy import Column, Integer, String
from .database import Base # 从我们刚创建的database.py中导入Base

# 创建一个Post模型,它将映射到数据库中的'posts'表
class Post(Base):
__tablename__ = "posts" # 表名

# 定义表的列
id = Column(Integer, primary_key=True, index=True) # id,主键,并建立索引
title = Column(String, index=True) # 标题,并建立索引
content = Column(String) # 内容

第三步:创建Pydantic数据模式 (schemas.py)
为什么需要这个文件? models.py 定义了数据在数据库中的样子,而 schemas.py 定义了数据在 API 中应该是什么样子。这样做可以将数据库层和API层解耦,更安全、更清晰。

在 backend 目录下创建 schemas.py 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# backend/schemas.py

from pydantic import BaseModel

# 定义基础的Post模式
class PostBase(BaseModel):
title: str
content: str | None = None # content是可选的

# 用于创建Post的模式,继承自PostBase
class PostCreate(PostBase):
pass # 创建时不需要额外字段

# 用于从API读取(返回)Post的模式
class Post(PostBase):
id: int # 读取时需要返回id

class Config:
orm_mode = True # 这个配置告诉Pydantic模型可以从ORM对象中读取数据

第四步:创建数据库操作函数 (crud.py)
我们将所有直接与数据库交互的函数(增删改查)都放在这个文件里。

在 backend 目录下创建 crud.py 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# backend/crud.py

from sqlalchemy.orm import Session
from . import models, schemas # 导入模型和模式

# 根据ID查询单个Post
def get_post(db: Session, post_id: int):
return db.query(models.Post).filter(models.Post.id == post_id).first()

# 查询所有Post(支持分页)
def get_posts(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Post).offset(skip).limit(limit).all()

# 创建一个新的Post
def create_post(db: Session, post: schemas.PostCreate):
# 用schemas.PostCreate的数据创建一个models.Post实例
db_post = models.Post(title=post.title, content=post.content)
db.add(db_post) # 添加到会话
db.commit() # 提交到数据库以保存
db.refresh(db_post) # 刷新实例以获取数据库生成的数据(如ID)
return db_post

第五步:整合到主应用 (main.py)
现在,我们来改造 main.py,让它使用我们刚刚创建的所有模块。

用以下内容完全替换 backend/main.py 里的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# backend/main.py

from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session

# 从同级目录导入我们创建的模块
from . import crud, models, schemas
from .database import SessionLocal, engine

# 根据我们的模型在数据库中创建表
models.Base.metadata.create_all(bind=engine)

app = FastAPI()

# --- CORS配置 (保持不变) ---
from fastapi.middleware.cors import CORSMiddleware
origins = ["http://localhost:5173", "http://127.0.0.1:5173"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# --- CORS配置结束 ---


# --- 依赖项 ---
# 定义一个依赖项,它为每个请求创建一个新的数据库会话
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()


# --- API 端点 ---

# 创建一个新Post
# response_model=schemas.Post 告诉FastAPI响应体将符合Post模式
@app.post("/api/posts/", response_model=schemas.Post)
def create_new_post(post: schemas.PostCreate, db: Session = Depends(get_db)):
# 直接调用crud函数
return crud.create_post(db=db, post=post)

# 获取所有Post
@app.get("/api/posts/", response_model=list[schemas.Post])
def read_posts(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
posts = crud.get_posts(db, skip=skip, limit=limit)
return posts

# 获取单个Post
@app.get("/api/posts/{post_id}", response_model=schemas.Post)
def read_post(post_id: int, db: Session = Depends(get_db)):
db_post = crud.get_post(db, post_id=post_id)
if db_post is None:
raise HTTPException(status_code=404, detail="Post not found")
return db_post

第六步:验证成果
1.启动后端服务:在你的后端终端,像之前一样启动服务:

1
uvicorn main:app --reload

当你第一次运行此命令后,你会发现在 backend 目录下多出了一个 blog.db 文件。这就是你的SQLite数据库!models.Base.metadata.create_all(bind=engine) 这行代码已经自动为你创建了posts表。

  • 拓展 python包管理
    为了让Python更明确地将一个文件夹识别为“包”,最佳实践是在这个文件夹里放一个空的 文件。init.py
    这个文件不需要任何内容,它的存在本身就是一个信号。

2.检查前端:刷新你的浏览器 。页面现在应该是空的,只显示标题,因为数据库里还没有任何文章。这是正常的。http://localhost:5173

3.创建第一篇文章:

打开浏览器的一个新标签页,访问 http://127.0.0.1:8000/docs。 这是FastAPI自动生成的交互式API文档。

找到绿色的 路径,点击它展开。POST /api/posts/

点击右上角的 “Try it out” 按钮。
在 “Request body” 中输入你的第一篇文章内容,例如:

1
2
3
4
{
"title": "我的第一篇数据库文章",
"content": "内容存储在SQLite中!"
}

点击下方的 “Execute” 按钮。

最终验证:如果执行成功(Response code 200),现在回到你的前端页面 http://localhost:5173 并刷新它。