FastAPI 的数据库与表单操作详解

377 阅读4分钟

FastAPI 是一个现代、高性能的 Python Web 框架,基于 Starlette 和 Pydantic,支持异步编程,非常适合构建高效的 API。本文将详细介绍如何在 FastAPI 中使用 MySQL 数据库操作和处理表单数据,并通过具体实例展示其实现过程。

1. FastAPI 与 MySQL 数据库集成

在 FastAPI 中,我们将使用 SQLAlchemy 作为 ORM 工具,并结合 MySQL 数据库进行操作。

1.1 安装必要的依赖

首先,确保安装 FastAPI、SQLAlchemy 以及 MySQL 的 Python 驱动(推荐 PyMySQL):

pip install fastapi uvicorn sqlalchemy pymysql

1.2 配置 MySQL 数据库连接

我们需要配置 MySQL 数据库连接并定义模型。以下是一个示例:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# MySQL 数据库连接 URL
# 格式:mysql+pymysql://用户名:密码@主机:端口/数据库名
DATABASE_URL = "mysql+pymysql://root:your_password@localhost:3306/test_db"

# 创建引擎
engine = create_engine(DATABASE_URL)

# 创建会话工厂
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建 Base 类,用于定义模型
Base = declarative_base()

# 定义 User 模型
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(50), index=True)  # MySQL 需要指定字符串长度
    email = Column(String(100), unique=True, index=True)

# 创建表(如果表不存在)
Base.metadata.create_all(bind=engine)

注意事项:

  • 替换 DATABASE_URL 中的 root:your_password@localhost:3306/test_db 为你的实际 MySQL 用户名、密码、主机、端口和数据库名。
  • 在运行代码前,确保 MySQL 服务已启动,并已创建名为 test_db 的数据库(可以用 CREATE DATABASE test_db; 命令创建)。

1.3 依赖注入获取数据库会话

与 SQLite 示例类似,我们使用依赖注入管理 MySQL 会话:

from fastapi import Depends

# 获取数据库会话的依赖函数
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

1.4 创建 API 端点操作数据库

以下是一个基于 MySQL 的增删改查(CRUD)示例:

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

app = FastAPI()

# Pydantic 模型,用于请求和响应
class UserCreate(BaseModel):
    name: str
    email: str

class UserResponse(BaseModel):
    idint
    name: str
    email: str

    class Config:
        orm_mode = True

# 创建用户
@app.post("/users/", response_model=UserResponse)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
    db_user = User(name=user.name, email=user.email)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

# 获取所有用户
@app.get("/users/", response_model=list[UserResponse])
def read_users(db: Session = Depends(get_db)):
    return db.query(User).all()

# 获取单个用户
@app.get("/users/{user_id}", response_model=UserResponse)
def read_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    if user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return user

运行代码:

uvicorn main:app --reload

访问 http://127.0.0.1:8000/docs,即可通过 Swagger UI 测试这些端点。

2. FastAPI 中的表单处理

表单处理逻辑与数据库类型无关,因此与 SQLite 示例相同。以下仅简要说明,完整代码见下文综合实例。

2.1 安装依赖

确保安装 python-multipart 以支持表单数据解析:

pip install python-multipart

2.2 处理简单表单

示例代码:

from fastapi import Form

@app.post("/login/")
async def login(username: str = Form(...), password: str = Form(...)):
    return {"username": username, "password": password}

2.3 处理文件上传表单

示例代码:

from fastapi import File, UploadFile

@app.post("/upload/")
async def upload_file(username: str = Form(...), file: UploadFile = File(...)):
    content = await file.read()
    return {"username": username, "filename": file.filename, "content": content.decode()}

3. 综合实例:用户注册与文件上传

以下是一个结合 MySQL 数据库和表单操作的完整示例:

from fastapi import FastAPI, Form, File, UploadFile, Depends, HTTPException
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

app = FastAPI()

# MySQL 数据库配置
DATABASE_URL = "mysql+pymysql://root:your_password@localhost:3306/test_db"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(50), index=True)
    email = Column(String(100), unique=True, index=True)

Base.metadata.create_all(bind=engine)

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# Pydantic 模型
class UserCreate(BaseModel):
    name: str
    email: str

    class Config:
        orm_mode = True

# 注册用户并上传头像
@app.post("/register/", response_model=UserCreate)
async def register(
    name: str = Form(...),
    email: str = Form(...),
    avatar: UploadFile = File(...),
    db: Session = Depends(get_db)
):
    # 检查用户是否已存在
    if db.query(User).filter(User.email == email).first():
        raise HTTPException(status_code=400, detail="Email already registered")
    
    # 保存文件(简单示例,实际应存储到文件系统)
    avatar_content = await avatar.read()
    with open(f"uploads/{avatar.filename}""wb"as f:
        f.write(avatar_content)
    
    # 保存用户信息到数据库
    db_user = User(name=name, email=email)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

# 获取用户列表
@app.get("/users/", response_model=list[UserCreate])
def get_users(db: Session = Depends(get_db)):
    return db.query(User).all()

3.1 运行程序准备

  1. MySQL 服务已启动。
  2. 已创建 test_db 数据库。
  3. 在项目目录下创建 uploads 文件夹以存储上传文件。

3.2 运行程序

uvicorn main:app --reload

3.3 测试方法

  • 注册用户并上传文件:
curl -X POST "http://127.0.0.1:8000/register/" -F "name=Alice" -F "email=alice@example.com" -F "avatar=@avatar.jpg"
  • 获取用户列表:
curl "http://127.0.0.1:8000/users/"

4. 总结

通过上述内容,我们详细介绍了 FastAPI 如何与 MySQL 数据库和表单数据集成:

  • MySQL 数据库操作:使用 SQLAlchemy 配置 MySQL 连接,定义模型并实现 CRUD 操作。
  • 表单处理:通过 Form 和 File 处理普通表单和文件上传,与数据库操作无缝结合。
  • 综合应用:展示了用户注册、文件上传和 MySQL 数据库操作的完整流程。

FastAPI 的异步支持和类型注解使其在开发高效 API 时非常强大。

5. 联系方式