VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • FastAPI与SQLAlchemy同步数据库集成

  1. FastAPI与SQLAlchemy同步数据库集成基础
    1.1 ORM框架核心原理
    ORM(Object-Relational Mapping)相当于数据库世界的翻译官,将Python类对象与数据库表进行双向转换。就像邮局工作人员把信件分拣到不同国家的邮筒,ORM自动将类属性映射为表字段,将对象操作转换为SQL语句。

SQLAlchemy作为Python最强大的ORM工具,提供两种模式:

Core层:SQL表达式语言,直接操作SQL抽象层
ORM层:声明式模型,面向对象方式操作数据库
FastAPI选择ORM层实现数据库集成,因其符合Pythonic编程风格,且能与Pydantic完美配合。

1.2 声明式模型定义
声明式模型就像建筑蓝图,通过类定义描述数据库结构。我们使用declarative_base()创建基类,所有模型继承这个基类获得映射能力。

# 安装必要库(运行环境要求Python3.7+)
# pip install fastapi sqlalchemy pydantic uvicorn

from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime

# 创建基类(相当于所有模型的DNA)
Base = declarative_base()


class User(Base):
    __tablename__ = 'users'  # 数据库表名

    id = Column(Integer, primary_key=True, index=True)
    username = Column(String(50), unique=True, nullable=False)
    email = Column(String(100), index=True)
    created_at = Column(DateTime, default=datetime.utcnow)

    def __repr__(self):
        return f"<User {self.username}>"

字段类型映射关系:

Python类型 SQL类型 说明
Integer INTEGER 32位整数
String(50) VARCHAR(50) 变长字符串,需指定长度
DateTime DATETIME 日期时间类型
Boolean BOOLEAN 布尔值
Float FLOAT 浮点数
1.3 数据库连接配置    
数据库引擎是ORM与数据库的通信枢纽,连接字符串格式:dialect+driver://user:password@host:port/dbname    
# 创建数据库引擎(同步模式)
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(
    DATABASE_URL,
    connect_args={"check_same_thread": False}  # 仅SQLite需要
)

# 创建所有表结构(相当于根据蓝图盖房子)
Base.metadata.create_all(bind=engine)

1.4 会话管理机制
数据库会话(Session)是工作单元模式的核心,管理所有数据库操作的生命周期。就像银行柜台办理业务,所有操作在窗口打开时开始,关闭时统一提交。

from sqlalchemy.orm import sessionmaker

# 创建会话工厂(相当于银行窗口)
SessionLocal = sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine
)


# 依赖项注入(FastAPI最佳实践)
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
  1. 完整集成示例
    2.1 用户管理API实现
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
from typing import Optional

app = FastAPI()


# Pydantic模型(数据验证层)
class UserCreate(BaseModel):
    username: str
    email: Optional[str] = None


class UserResponse(UserCreate):
    id: int
    created_at: datetime


# 创建用户端点
@app.post("/users/", response_model=UserResponse)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
    # 检查用户名是否重复
    db_user = db.query(User).filter(User.username == user.username).first()
    if db_user:
        raise HTTPException(status_code=400, detail="Username already registered")

    # 创建ORM对象
    db_user = User(**user.dict())
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

2.2 查询接口实现

@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 not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user
  1. 常见问题解决方案
    3.1 数据库会话报错处理
    报错信息:sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table

解决方案:

检查是否调用Base.metadata.create_all(bind=engine)
确认数据库文件路径正确
确保模型类正确定义了__tablename__
3.2 数据验证错误
报错信息:422 Unprocessable Entity,请求体验证失败

排查步骤:

检查Pydantic模型字段类型定义
验证请求Content-Type是否为application/json
使用Swagger UI测试接口,观察请求示例格式
课后Quiz
问题1:当需要添加用户年龄字段时,应如何修改模型?

A. 同时在SQLAlchemy模型和Pydantic模型中添加字段
B. 只需修改SQLAlchemy模型
C. 需要同时修改SQLAlchemy模型和Pydantic模型,并执行数据库迁移

答案:C
解析:SQLAlchemy模型负责数据库结构,Pydantic模型负责数据验证。新增字段需两者同时修改,并通过迁移工具更新数据库表结构。

问题2:如何防止用户注册时邮箱重复?

A. 在数据库层面设置唯一约束
B. 在业务逻辑中先查询是否存在
C. 同时使用A和B

答案:C
解析:数据库唯一约束是最终保障,业务逻辑中的检查能提前发现错误,提升系统友好性。两者结合是最佳实践。

  1. 高级配置技巧
    4.1 复合索引优化
from sqlalchemy import Index


class Product(Base):
    __tablename__ = 'products'
    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    category = Column(String(50))
    price = Column(Integer)


# 创建复合索引(名称+类别)
__table_args__ = (
    Index('idx_name_category', 'name', 'category'),
)

4.2 事务管理示例

def transfer_funds(sender_id, receiver_id, amount, db):
    try:
        sender = db.query(User).get(sender_id)
        receiver = db.query(User).get(receiver_id)

        if sender.balance < amount:
            raise ValueError("Insufficient balance")

        sender.balance -= amount
        receiver.balance += amount

        db.commit()
    except:
        db.rollback()
        raise

运行服务:

uvicorn main:app --reload
来源:https://www.cnblogs.com/Amd794/p/18825992


相关教程