在現代應用開發中,快速構建數據庫驅動的API服務是常見需求。FastAPI作爲高性能Python框架,結合SQLite這一輕量級嵌入式數據庫,能幫助我們快速實現簡單但實用的後端服務。本文將通過一個完整的“學生信息管理”示例,手把手帶你從0到1搭建一個數據庫API服務。
一、環境準備:安裝必要工具¶
首先,我們需要安裝FastAPI、SQLite的Python接口(SQLAlchemy,用於ORM操作)和服務器(Uvicorn)。打開終端,執行以下命令:
pip install fastapi uvicorn sqlalchemy
- FastAPI:Python高性能Web框架,自動生成API文檔,支持異步操作。
- Uvicorn:ASGI服務器,用於運行FastAPI應用。
- SQLAlchemy:ORM(對象關係映射)庫,讓Python代碼可直接操作數據庫,無需寫原生SQL。
- SQLite:無需獨立服務器的嵌入式數據庫,適合開發和小型項目。
二、核心概念:數據模型與數據庫連接¶
我們以“學生信息”爲例,先定義數據模型和數據庫連接。創建一個main.py文件,按以下步驟編寫代碼:
1. 導入依賴¶
from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from pydantic import BaseModel
2. 定義數據模型¶
使用SQLAlchemy定義數據庫表結構(ORM模型),這裏我們創建一個Student模型,對應數據庫中的students表:
# 1. 連接SQLite數據庫(文件存儲,無需額外服務器)
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" # 數據庫文件路徑爲當前目錄下的test.db
# 2. 創建SQLAlchemy引擎(核心連接對象)
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} # SQLite專用參數
)
# 3. 創建會話本地類(用於操作數據庫)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 4. 定義基類(所有ORM模型繼承自它)
Base = declarative_base()
# 5. 定義Student模型(對應數據庫表)
class Student(Base):
__tablename__ = "students" # 表名
id = Column(Integer, primary_key=True, index=True) # 主鍵,自增
name = Column(String, index=True, nullable=False) # 學生姓名(非空)
age = Column(Integer, nullable=True) # 學生年齡(可選)
3. 創建數據庫表¶
在第一次運行時,需要創建表結構。可以通過SQLAlchemy的create_all()方法自動生成表:
# 創建所有表(需在定義完模型後執行)
Base.metadata.create_all(bind=engine)
4. 定義Pydantic模型(數據驗證與序列化)¶
FastAPI需要明確請求/響應的數據格式,我們用Pydantic定義數據模型:
# 用於請求數據的模型(無需id,由數據庫自動生成)
class StudentCreate(BaseModel):
name: str
age: int | None = None # 年齡可選
# 用於響應數據的模型(包含id)
class StudentResponse(BaseModel):
id: int
name: str
age: int | None = None
class Config:
orm_mode = True # 允許從ORM對象(SQLAlchemy模型)中讀取數據
三、數據庫操作函數(CRUD)¶
接下來,編寫操作數據庫的函數(CRUD:創建、讀取、更新、刪除)。我們通過SQLAlchemy的會話(Session)執行數據庫操作:
# 依賴項:獲取數據庫會話(每次請求生成新會話,用完關閉)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# 1. 創建學生(POST /students)
def create_student(db: Session, student: StudentCreate):
db_student = Student(name=student.name, age=student.age)
db.add(db_student)
db.commit()
db.refresh(db_student) # 刷新數據,獲取數據庫生成的id
return db_student
# 2. 獲取單個學生(GET /students/{student_id})
def get_student(db: Session, student_id: int):
return db.query(Student).filter(Student.id == student_id).first()
# 3. 獲取所有學生(GET /students)
def get_all_students(db: Session, skip: int = 0, limit: int = 100):
return db.query(Student).offset(skip).limit(limit).all()
# 4. 更新學生(PUT /students/{student_id})
def update_student(db: Session, student_id: int, student_update: StudentCreate):
db_student = get_student(db, student_id)
if not db_student:
return None
# 更新字段(僅name和age,id不可修改)
db_student.name = student_update.name
db_student.age = student_update.age
db.commit()
db.refresh(db_student)
return db_student
# 5. 刪除學生(DELETE /students/{student_id})
def delete_student(db: Session, student_id: int):
db_student = get_student(db, student_id)
if not db_student:
return False
db.delete(db_student)
db.commit()
return True
四、搭建FastAPI路由(API端點)¶
現在,將CRUD函數與FastAPI路由綁定,實現具體的API接口:
# 創建FastAPI實例
app = FastAPI(title="學生信息管理API")
# 1. 創建學生(POST請求)
@app.post("/students", response_model=StudentResponse, status_code=201)
def create_student_endpoint(student: StudentCreate, db: Session = Depends(get_db)):
db_student = create_student(db=db, student=student)
return db_student
# 2. 獲取單個學生(GET請求)
@app.get("/students/{student_id}", response_model=StudentResponse)
def get_student_endpoint(student_id: int, db: Session = Depends(get_db)):
db_student = get_student(db, student_id)
if not db_student:
raise HTTPException(status_code=404, detail="學生不存在")
return db_student
# 3. 獲取所有學生(GET請求)
@app.get("/students", response_model=list[StudentResponse])
def get_all_students_endpoint(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
students = get_all_students(db, skip=skip, limit=limit)
return students
# 4. 更新學生(PUT請求)
@app.put("/students/{student_id}", response_model=StudentResponse)
def update_student_endpoint(student_id: int, student: StudentCreate, db: Session = Depends(get_db)):
db_student = update_student(db, student_id, student)
if not db_student:
raise HTTPException(status_code=404, detail="學生不存在")
return db_student
# 5. 刪除學生(DELETE請求)
@app.delete("/students/{student_id}", status_code=204)
def delete_student_endpoint(student_id: int, db: Session = Depends(get_db)):
success = delete_student(db, student_id)
if not success:
raise HTTPException(status_code=404, detail="學生不存在")
return None
五、運行與測試API服務¶
1. 啓動應用¶
在終端執行以下命令啓動服務(--reload開啓熱重載,修改代碼後自動重啓):
uvicorn main:app --reload
main:文件名(main.py)app:FastAPI實例名- 啓動後,訪問
http://127.0.0.1:8000/docs或http://127.0.0.1:8000/redoc可查看交互式API文檔。
2. 測試API¶
使用FastAPI的交互式文檔(Swagger UI)或命令行工具測試:
-
創建學生:
點擊/docs中的POST /students→ 點擊“Try it out” → 輸入JSON數據(如{"name": "Alice", "age": 20})→ 點擊“Execute”。 -
獲取單個學生:
點擊GET /students/{student_id}→ 輸入剛創建的學生ID(如1)→ 點擊“Execute”。 -
其他操作:
同理測試GET /students(獲取所有)、PUT /students/{id}(更新)、DELETE /students/{id}(刪除)。
六、總結¶
通過本文,你已完成一個基於FastAPI+SQLite的輕量級數據庫API服務。核心優勢包括:
- 輕量易用:SQLite無需額外服務器,FastAPI自動生成API文檔,降低開發門檻。
- 高性能:FastAPI支持異步操作,適合高併發場景(但SQLite本身是單線程,適合中小規模)。
- 擴展性強:可通過修改SQLAlchemy模型和路由,快速支持複雜業務(如多表關聯、權限控制)。
後續可嘗試擴展:添加分頁、過濾、排序功能,或遷移到PostgreSQL/MySQL等數據庫。
完整代碼示例(可直接複製到main.py運行):
from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from pydantic import BaseModel
# 數據庫配置
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# 學生模型(數據庫表)
class Student(Base):
__tablename__ = "students"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True, nullable=False)
age = Column(Integer, nullable=True)
Base.metadata.create_all(bind=engine) # 創建表
# Pydantic模型(數據驗證)
class StudentCreate(BaseModel):
name: str
age: int | None = None
class StudentResponse(BaseModel):
id: int
name: str
age: int | None = None
class Config:
orm_mode = True
# 數據庫會話依賴
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# 數據庫操作函數
def create_student(db: Session, student: StudentCreate):
db_student = Student(name=student.name, age=student.age)
db.add(db_student)
db.commit()
db.refresh(db_student)
return db_student
def get_student(db: Session, student_id: int):
return db.query(Student).filter(Student.id == student_id).first()
def get_all_students(db: Session, skip: int = 0, limit: int = 100):
return db.query(Student).offset(skip).limit(limit).all()
def update_student(db: Session, student_id: int, student: StudentCreate):
db_student = get_student(db, student_id)
if not db_student:
return None
db_student.name = student.name
db_student.age = student.age
db.commit()
db.refresh(db_student)
return db_student
def delete_student(db: Session, student_id: int):
db_student = get_student(db, student_id)
if not db_student:
return False
db.delete(db_student)
db.commit()
return True
# FastAPI應用
app = FastAPI(title="學生信息API")
# API路由
@app.post("/students", response_model=StudentResponse, status_code=201)
def create_student_endpoint(student: StudentCreate, db: Session = Depends(get_db)):
return create_student(db, student)
@app.get("/students/{student_id}", response_model=StudentResponse)
def get_student_endpoint(student_id: int, db: Session = Depends(get_db)):
student = get_student(db, student_id)
if not student:
raise HTTPException(status_code=404, detail="學生不存在")
return student
@app.get("/students", response_model=list[StudentResponse])
def get_all_students_endpoint(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
return get_all_students(db, skip, limit)
@app.put("/students/{student_id}", response_model=StudentResponse)
def update_student_endpoint(student_id: int, student: StudentCreate, db: Session = Depends(get_db)):
updated = update_student(db, student_id, student)
if not updated:
raise HTTPException(status_code=404, detail="學生不存在")
return updated
@app.delete("/students/{student_id}", status_code=204)
def delete_student_endpoint(student_id: int, db: Session = Depends(get_db)):
success = delete_student(db, student_id)
if not success:
raise HTTPException(status_code=404, detail="學生不存在")
return None