实际代码操作知识点分析:SQLAlchemy+FastAPI + 异步MySQL 全流程解析 + 增删改查逐行注释

文章目录

一、代码全流程(数字顺序,核心步骤)

代码内容:

python 复制代码
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
from starlette import status

# 创建FastAPI对象
app = FastAPI()

# 工具模块
# 工具模块通常写一些 创建数据库引擎 获取Session....
from datetime import datetime

from sqlalchemy import DateTime, func, String, Float, Select, Insert, Delete, select, ForeignKey
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

# 链接数据库的url地址
DATABASE_URL = "mysql+aiomysql://root:root@localhost:3306/fastapi_review?charset=utf8"

# 1. 异步数据库引擎
'''
启用 SQL 日志:echo=True 会在控制台输出执行的 SQL 语句,便于调试
连接池配置:
pool_size=10:连接池基础大小为 10 个连接
max_overflow=20:最大溢出连接数为 20(即最多可有 30 个并发连接)
'''
engine = create_async_engine(DATABASE_URL, echo=True, pool_size=10, max_overflow=20)


# 2. 建立模型映射。不成文的规定(阿里)
class Base(DeclarativeBase):
    # 创建时间
    create_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)

    # 更新时间
    update_time: Mapped[datetime] = mapped_column(DateTime,
                                                  default=datetime.now,
                                                  onupdate=func.now(),
                                                  insert_default=func.now()
                                                  )


class Department(Base):
    __tablename__ = "t_department"

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, name="department_id",
                                    comment="部门ID")
    name: Mapped[str] = mapped_column(String(20), nullable=False, name="department_name",
                                      comment="部门名称")
    location: Mapped[str] = mapped_column(String(100), nullable=False, name="department_location",
                                      comment="部门位置")

    def __str__(self):
        return f"Department(id={self.id}, name={self.name}, location={self.location})"


class User(Base):
    __tablename__ = "t_user"

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, name="user_id",
                                    comment="用户ID")
    name: Mapped[str] = mapped_column(String(20), nullable=False, name="user_name",
                                      comment="用户名称")
    password: Mapped[str] = mapped_column(String(20), nullable=False, name="user_password",
                                          comment="用户密码")
    salary: Mapped[float] = mapped_column(Float(6, 2), nullable=False, name="user_salary",
                                          comment="用户薪水")
    birthday: Mapped[datetime] = mapped_column(DateTime, nullable=False, name="user_birthday",
                                               comment="用户出生日期")
    department_id: Mapped[int] = mapped_column(ForeignKey("t_department.department_id"),
                                               nullable=False, name="department_id",
                                               comment="部门ID")

    def __str__(self):
        return f"User(id={self.id}, name={self.name}, password={self.password}, salary={self.salary}, birthday={self.birthday}, department_id={self.department_id})"


# 3. 创建表
async def create_tables():
    # 获取异步引擎,创建事务 - 建表
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)  # Base 模型类的元数据创建


# 事件监听器。事件 监听器(容器监听)当容器一启动,创建事件对象("startup")。就会动态调用此函数
@app.on_event("startup")
async def init():
    await create_tables()


# 4. 异步Session工厂
AsyncSessionLocal = async_sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False)


# 5.创建依赖项
async def get_session():
    async with AsyncSessionLocal() as session:
        try:
            yield session
            await session.commit()
        except Exception as e:
            await session.rollback()
        finally:
            await session.close()


@app.get("/users")
async def get_user_list(session: AsyncSession = Depends(get_session)):
    """
    查询所有用户
    :param session:
    :return:
    """

    # 1.生成语句对象
    stmt = Select(User)

    # 2.执行语句对象 发SQL
    result = await session.execute(stmt)

    # 3.获取结果
    user_list = result.scalars().all()
    return user_list


# 条件查询
@app.get("/users/")
async def get_user_by_name(name: str, session: AsyncSession = Depends(get_session)):
    """
    根据用户名称精确查询用户列表
    :param name: 用户名称
    :param session: 会话
    :return: 用户列表
    """
    stmt = Select(User).where(User.name == name)
    result = await session.execute(stmt)
    user_list = result.scalars().all()
    return user_list


@app.get("/users/like/")
async def get_user_like_name(name: str, session: AsyncSession = Depends(get_session)):
    """
    根据用户名称模糊查询用户列表
    :param name: 用户名称
    :param session: 会话
    :return: 用户列表
    """

    # user_name like '%z%'
    stmt = Select(User).where(User.name.like(f"%{name}%"))
    result = await session.execute(stmt)
    user_list = result.scalars().all()
    return user_list


# http://localhost:8888/users/in/?ids=2,4    查询参数
@app.get("/users/in/")
async def get_user_in_ids(ids: str, session: AsyncSession = Depends(get_session)):
    # ["2","4"] ------> [2,4]
    id_list = ids.split(",")
    id_final_list = []

    for item in id_list:
        temp = int(item)
        id_final_list.append(temp)

    # 可以使用lambda函数(匿名函数)
    # map(int, id_list)

    # select * from t_user where user_id in (2,4)
    stmt = Select(User).where(User.id.in_(id_final_list))
    result = await session.execute(stmt)
    user_list = result.scalars().all()
    return user_list


@app.get("/users/between/{min_salary}/{max_salary}")
async def get_user_between_salary(min_salary: float,
                                  max_salary: float,
                                  session: AsyncSession = Depends(get_session)):
    """
    根据用户薪资范围查询用户列表
    :param min_salary: 薪资最小薪资
    :param max_salary: 薪资最大薪资
    :param session: 会话
    :return: 用户列表
    """

    # user_name like '%z%'
    stmt = Select(User).where(User.salary.between(min_salary, max_salary))
    result = await session.execute(stmt)
    user_list = result.scalars().all()
    return user_list


@app.get("/users/{id}")
async def get_user_by_id(id: int,
                         session: AsyncSession = Depends(get_session)):
    """
    根据用户薪资范围查询用户列表
    :param min_salary: 薪资最小薪资
    :param max_salary: 薪资最大薪资
    :param session: 会话
    :return: 用户列表
    """

    # user_name like '%z%'
    # stmt = Select(User).where(User.id == id)
    # result = await session.execute(stmt)
    # user = result.scalar()

    user = await session.get(User, id)
    return user


@app.get("/users/page/{page_no}/{page_size}")
async def get_user_by_id(page_no: int, page_size: int,
                         session: AsyncSession = Depends(get_session)):
    """
    根据用户薪资范围查询用户列表
    :param min_salary: 薪资最小薪资
    :param max_salary: 薪资最大薪资
    :param session: 会话
    :return: 用户列表
    """

    stmt = Select(User).offset((page_no - 1) * page_size).limit(page_size)
    result = await session.execute(stmt)
    user_list = result.scalars().all()
    return user_list


# 利用Pydantic验证模型数据
class UserRequest(BaseModel):
    name: str
    password: str
    salary: float
    birthday: datetime


class UserUpdate(BaseModel):
    id: int
    name: str
    password: str
    salary: float
    birthday: datetime


# 添加用户
@app.post("/users")
async def add_user(user: UserRequest, session: AsyncSession = Depends(get_session)):
    # if user is None:
    #     # 抛出异常
    #     raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="用户信息不能为空")
    # stmt = Insert(User).values(**user.__dict__)
    # await session.execute(stmt)
    # # await session.commit()


    # 另外一种实现方式:将pydantic类型(UserRequest)转换成数据库类型(User)对象
    name = user.name
    password = user.password
    salary = user.salary
    birthday = user.birthday

    # 封装成User类型的对象
    user_object = User(name=name, password=password, salary=salary, birthday=birthday)
    session.add(user_object)

    return {
        "code": 200,
        "message": "添加成功"
    }


# 删除用户,根据用户编号删除用户
@app.delete("/users/{id}")
async def delete_user(id: int, session: AsyncSession = Depends(get_session)):
    # stmt = Select(User).where(User.id == id)
    # result = await session.execute(stmt)
    #
    # # 查询了一个对象,要么就是None,要么就一个对象
    # user = result.scalar_one_or_none()
    #
    # if user is None:
    #     raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,detail="用户不存在")

    # 1. 有时候我们做删除还需要判断该用户是否有关联对象,如果存在关联对象,那么势必需要先处理关系后再做删除
    # 2. 真正的开发中删除操作基本都是逻辑删除(只是修改状态 is_deleted = True),不会物理删除。

    stmt = Delete(User).where(User.id == id)
    await session.execute(stmt)
    await session.commit()
    return {
        "code": 200,
        "message": "删除成功"
    }


@app.put("/users/{id}")
async def update_user(id: int, user_request: UserRequest,
                      session: AsyncSession = Depends(get_session)):
    """

    :param id: 用户编号
    :param user_request: 从前端传递的请求体数据。这些数据是全新数据
    :param session:
    :return:
    """
    # TODO 1. 根据id查询用户得到user_object
    stmt = Select(User).where(User.id == id)
    result = await session.execute(stmt)
    user = result.scalar_one_or_none()

    # TODO 将新数据(user_request)中的各个属性值覆盖掉user_object对象中的属性
    user.name = user_request.name
    user.password = user_request.password
    user.salary = user_request.salary
    user.birthday = user_request.birthday

    return {
        "code": 200,
        "message": "修改成功"
    }



class DepartmentRequest(BaseModel):
    name: str
    location: str

class DepartmentAddRequest(DepartmentRequest):
    users: list[UserRequest]



# TODO添加部门的同时,初始化用户数据
@app.post("/departments/")
async def add_department(department_add_request: DepartmentAddRequest,
                         session: AsyncSession = Depends(get_session)):
    if department_add_request is None:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="部门信息不能为空")

    if department_add_request.users is None:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="用户信息不能为空")

    # 1. 先添加部门
    # session.add(depart) → 对象进入 pending 状态,此时 depart.id 是 None
    # session.flush()(commit() 内部会先 flush)→ SQLAlchemy 发 INSERT SQL,数据库返回自增主键,SQLAlchemy 把这个 id 回填到 depart.id 上
    # session.commit() → 真正提交事务
    depart = Department(name=department_add_request.name, location=department_add_request.location)
    session.add(depart)
    await session.commit()

    # ???为什么这里需要刷新?
    # refresh() 的作用是 重新发一条 SELECT 语句,把数据库里这一行的全部字段重新加载回对象,主要用来同步:
    #
    # 数据库端计算的字段(如 server_default、触发器、func.now() 写进 DB 的默认值)
    # 并发场景下可能被别人改过的字段
    # 被 expire 掉的属性
    # 对"只拿自增 id"这个需求来说,refresh 其实是多余的。
    session.refresh(depart)

    # 2. 遍历用户列表,用户的department_id设置值,添加用户
    for user in department_add_request.users:
       user = User(name=user.name,
            password=user.password,
            salary=user.salary,
            birthday=user.birthday,
            department_id=depart.id)
       session.add(user)

    # await session.commit()
    return {
        "code": 200,
        "message": "添加成功"
    }


# TODO 删除部门。如果这个部门有员工,那能不能删的问题?根据需求来做
# 如果这个部门有员工,那么将这些员工的department_id设置为None,然后再删除部门

class UserDepartmentResponse(BaseModel):
    id: int
    name: str
    password: str
    salary: float
    birthday: datetime
    department_id: int
    department_name: str
    department_location: str

# TODO 根据部门名称查询该部门下的员工以及部门信息
@app.get("/api/users/{name}")
async def get_users_by_department_name(name: str, session: AsyncSession = Depends(get_session)):
    stmt = select(User,Department).join(Department,User.department_id == Department.id).where(
        Department.name
                                                                                  == name)

    # result内部持有一个什么类型的对象?元组
    result = await session.execute(stmt)

    # 此处不用再调用scalars()方法,因为已经查询到了元组
    user_list = result.all()

    user_department_list = []
    for item in user_list:
        user_obj = item[0]
        department_obj = item[1]
        user_department_response = UserDepartmentResponse(
            id=user_obj.id,
            name=user_obj.name,
            password=user_obj.password,
            salary=user_obj.salary,
            birthday=user_obj.birthday,
            department_id=user_obj.department_id,
            department_name=department_obj.name,
            department_location=department_obj.location
        )
        user_department_list.append(user_department_response)

    # # 根据部门名称查询部门
    #
    # # 组装数据(list[UserDepartmentResponse])
    # user_department_list = []

    return {
        "code": 200,
        "message": "查询成功",
        "data": user_department_list
    }


# TODO 根据用户名称查询该用户所在部门
@app.get("/departments/{name}")
async def get_department_by_user_name(name:str,
                                      session: AsyncSession = Depends(get_session)):
    # 优缺点:性能稍好,但是如果连接的表太多其实也会有性能损耗
    stmt = select(Department).join(User, Department.id == User.department_id).where(User.name == name)
    result = await session.execute(stmt)
    department = result.scalar_one_or_none()
    return {
        "code": 200,
        "message": "查询成功",
        "data": department
    }

    # 先根据用户名称查询部门编号
    # 根据部门编号查询部门

这是代码从启动到运行的完整逻辑,按顺序执行:

  1. 导入依赖库:引入FastAPI、数据库操作、数据验证等所有需要的工具
  2. 创建FastAPI应用:初始化项目核心对象,相当于项目的"总入口"
  3. 配置数据库连接 :填写MySQL地址,创建异步数据库引擎(专门负责和数据库通信)
  4. 定义数据库基类 :创建公共父类,自动给所有表添加创建/更新时间字段
  5. 定义数据表模型 :编写部门表用户表的结构(字段、类型、外键关联)
  6. 编写自动建表函数:项目启动时,自动在MySQL中创建对应的表
  7. 绑定启动事件:项目一运行,就自动执行建表操作
  8. 创建数据库会话工厂:批量生产"数据库连接对象",供接口使用
  9. 编写数据库依赖 :自动管理连接的创建、提交、回滚、关闭,不用手动写
  10. 定义数据验证模型:规范前端传入的数据格式,防止非法数据入库
  11. 编写用户CRUD接口 :实现用户的查询、新增、删除、修改核心功能
  12. 编写关联操作接口 :实现部门+用户联表操作(新增部门同步加用户、联表查询)
  13. 启动服务:所有接口就绪,可通过URL访问操作数据库

二、核心代码逐行解析

下面将分模块讲解,重点标注增删改查,每行代码都加注释+作用说明。

模块1:基础配置(导入+创建应用)

python 复制代码
# 导入FastAPI核心:应用对象、依赖注入、异常抛出
from fastapi import FastAPI, Depends, HTTPException
# 导入数据验证工具:严格校验前端传入的数据
from pydantic import BaseModel
# 导入HTTP状态码:比如400参数错误、200成功
from starlette import status

# ===================== 1. 创建FastAPI项目入口 =====================
# 创建FastAPI对象,整个项目的核心,所有接口都挂在这个对象上
app = FastAPI()

模块2:数据库核心配置(引擎+模型)

python 复制代码
# 导入时间工具、数据库字段类型、增删改查语句、异步数据库工具
from datetime import datetime
from sqlalchemy import DateTime, func, String, Float, Select, Insert, Delete, select, ForeignKey
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

# ===================== 2. 数据库连接配置 =====================
# 数据库连接地址:格式= 数据库类型+驱动://用户名:密码@主机:端口/库名?编码
DATABASE_URL = "mysql+aiomysql://root:root@localhost:3306/fastapi_review?charset=utf8"

# 创建异步数据库引擎:负责和MySQL建立通信,相当于"数据库桥梁"
# echo=True:控制台打印执行的SQL语句(方便调试)
# pool_size:连接池大小,控制并发连接数
engine = create_async_engine(DATABASE_URL, echo=True, pool_size=10, max_overflow=20)

# ===================== 3. 数据库模型基类 =====================
# 所有数据表的父类,统一添加公共字段(创建时间、更新时间)
class Base(DeclarativeBase):
    # 创建时间:插入数据时自动赋值为当前时间
    create_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
    # 更新时间:修改数据时自动更新为当前时间
    update_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.now, onupdate=func.now())

# ===================== 4. 定义部门表模型 =====================
class Department(Base):
    __tablename__ = "t_department"  # 数据库表名
    # 部门ID:主键、自增
    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, name="department_id", comment="部门ID")
    # 部门名称:字符串类型,不能为空
    name: Mapped[str] = mapped_column(String(20), nullable=False, name="department_name", comment="部门名称")
    # 部门位置:字符串类型,不能为空
    location: Mapped[str] = mapped_column(String(100), nullable=False, name="department_location", comment="部门位置")

# ===================== 5. 定义用户表模型 =====================
class User(Base):
    __tablename__ = "t_user"  # 数据库表名
    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, name="user_id", comment="用户ID")
    name: Mapped[str] = mapped_column(String(20), nullable=False, name="user_name", comment="用户名称")
    password: Mapped[str] = mapped_column(String(20), nullable=False, name="user_password", comment="用户密码")
    salary: Mapped[float] = mapped_column(Float(6, 2), nullable=False, name="user_salary", comment="用户薪水")
    birthday: Mapped[datetime] = mapped_column(DateTime, nullable=False, name="user_birthday", comment="出生日期")
    # 外键:关联部门表的主键,建立用户和部门的关联关系
    department_id: Mapped[int] = mapped_column(ForeignKey("t_department.department_id"), nullable=False, comment="部门ID")

模块3:自动建表 + 数据库依赖(核心工具)

python 复制代码
# ===================== 6. 异步建表函数 =====================
async def create_tables():
    # 打开数据库连接
    async with engine.begin() as conn:
        # 自动根据模型创建所有数据表(如果表不存在则创建,存在则不操作)
        await conn.run_sync(Base.metadata.create_all)

# 项目启动事件:服务一运行,自动执行建表函数
@app.on_event("startup")
async def init():
    await create_tables()

# ===================== 7. 数据库会话工厂 =====================
# 生产异步数据库连接(会话),所有接口都用这个连接操作数据库
AsyncSessionLocal = async_sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False)

# ===================== 8. 数据库依赖项(自动管理连接) =====================
async def get_session():
    # 创建数据库连接
    async with AsyncSessionLocal() as session:
        try:
            yield session  # 把连接交给接口使用
            await session.commit()  # 操作成功,自动提交事务
        except Exception as e:
            await session.rollback()  # 操作失败,自动回滚(数据不丢失)
        finally:
            await session.close()  # 操作完成,自动关闭连接

三、重点:增删改查接口逐行解析

模块4:数据验证模型(规范前端数据)

python 复制代码
# 新增用户的数据格式:前端必须传这4个参数,类型严格匹配
class UserRequest(BaseModel):
    name: str       # 用户名
    password: str   # 密码
    salary: float   # 薪资
    birthday: datetime # 生日

# 修改用户的数据格式:必须传用户ID
class UserUpdate(BaseModel):
    id: int
    name: str
    password: str
    salary: float
    birthday: datetime

核心1:查询操作(全解析)

python 复制代码
# ===================== 查询1:查询所有用户 =====================
@app.get("/users")  # 接口地址:GET请求
async def get_user_list(session: AsyncSession = Depends(get_session)):
    # 1. 生成SQL语句:select * from t_user
    stmt = Select(User)
    # 2. 执行SQL语句(异步执行,必须加await)
    result = await session.execute(stmt)
    # 3. 获取结果:转换为用户对象列表
    user_list = result.scalars().all()
    # 4. 返回数据给前端
    return user_list

# ===================== 查询2:根据用户名精确查询 =====================
@app.get("/users/")
async def get_user_by_name(name: str, session: AsyncSession = Depends(get_session)):
    # 生成SQL:select * from t_user where user_name = ?
    stmt = Select(User).where(User.name == name)
    result = await session.execute(stmt)
    return result.scalars().all()

# ===================== 查询3:模糊查询 =====================
@app.get("/users/like/")
async def get_user_like_name(name: str, session: AsyncSession = Depends(get_session)):
    # 生成SQL:select * from t_user where user_name like '%xxx%'
    stmt = Select(User).where(User.name.like(f"%{name}%"))
    result = await session.execute(stmt)
    return result.scalars().all()

# ===================== 查询4:ID范围查询 =====================
@app.get("/users/in/")
async def get_user_in_ids(ids: str, session: AsyncSession = Depends(get_session)):
    # 把字符串"2,4"转换为列表[2,4]
    id_list = [int(item) for item in ids.split(",")]
    # 生成SQL:select * from t_user where user_id in (2,4)
    stmt = Select(User).where(User.id.in_(id_list))
    result = await session.execute(stmt)
    return result.scalars().all()

# ===================== 查询5:薪资范围查询 =====================
@app.get("/users/between/{min_salary}/{max_salary}")
async def get_user_between_salary(min_salary: float, max_salary: float, session: AsyncSession = Depends(get_session)):
    # 生成SQL:select * from t_user where salary between 最小值 and 最大值
    stmt = Select(User).where(User.salary.between(min_salary, max_salary))
    result = await session.execute(stmt)
    return result.scalars().all()

# ===================== 查询6:根据ID查询单个用户 =====================
@app.get("/users/{id}")
async def get_user_by_id(id: int, session: AsyncSession = Depends(get_session)):
    # 快速根据主键查询:session.get(模型类, 主键值)
    user = await session.get(User, id)
    return user

# ===================== 查询7:分页查询 =====================
@app.get("/users/page/{page_no}/{page_size}")
async def get_user_by_id(page_no: int, page_size: int, session: AsyncSession = Depends(get_session)):
    # offset:跳过的条数;limit:查询的条数(分页核心)
    stmt = Select(User).offset((page_no - 1) * page_size).limit(page_size)
    result = await session.execute(stmt)
    return result.scalars().all()

核心2:新增操作(逐行注释)

python 复制代码
# ===================== 新增用户 =====================
@app.post("/users")  # POST请求:专门用于新增数据
async def add_user(user: UserRequest, session: AsyncSession = Depends(get_session)):
    # 1. 把前端传入的验证数据,封装为数据库用户对象
    user_object = User(
        name=user.name,
        password=user.password,
        salary=user.salary,
        birthday=user.birthday,
        department_id=1  # 补充外键(原代码缺失)
    )
    # 2. 将对象添加到数据库会话(准备插入)
    session.add(user_object)
    # 3. 返回成功提示(依赖项会自动commit提交)
    return {"code": 200, "message": "添加成功"}

核心3:删除操作(逐行注释)

python 复制代码
# ===================== 删除用户 =====================
@app.delete("/users/{id}")  # DELETE请求:专门用于删除数据
async def delete_user(id: int, session: AsyncSession = Depends(get_session)):
    # 1. 生成SQL:delete from t_user where user_id = ?
    stmt = Delete(User).where(User.id == id)
    # 2. 执行删除语句
    await session.execute(stmt)
    # 3. 返回成功提示
    return {"code": 200, "message": "删除成功"}

核心4:修改操作(逐行注释)

python 复制代码
# ===================== 修改用户 =====================
@app.put("/users/{id}")  # PUT请求:专门用于修改数据
async def update_user(id: int, user_request: UserRequest, session: AsyncSession = Depends(get_session)):
    # 1. 根据ID查询要修改的用户
    stmt = Select(User).where(User.id == id)
    result = await session.execute(stmt)
    user = result.scalar_one_or_none()

    # 2. 用新数据覆盖旧数据
    user.name = user_request.name
    user.password = user_request.password
    user.salary = user_request.salary
    user.birthday = user_request.birthday

    # 3. 返回成功提示
    return {"code": 200, "message": "修改成功"}

核心5:联表操作(部门+用户)

python 复制代码
# ===================== 新增部门+同步新增用户 =====================
@app.post("/departments/")
async def add_department(department_add_request: DepartmentAddRequest, session: AsyncSession = Depends(get_session)):
    # 1. 创建部门对象
    depart = Department(name=department_add_request.name, location=department_add_request.location)
    session.add(depart)
    await session.commit()  # 提交后才能获取部门自增ID
    session.refresh(depart)  # 同步部门ID到对象

    # 2. 遍历用户列表,绑定部门ID,批量新增用户
    for user in department_add_request.users:
        new_user = User(
            name=user.name, password=user.password, salary=user.salary,
            birthday=user.birthday, department_id=depart.id
        )
        session.add(new_user)

    return {"code": 200, "message": "添加成功"}

# ===================== 联表查询:根据部门名查用户+部门 =====================
@app.get("/api/users/{name}")
async def get_users_by_department_name(name: str, session: AsyncSession = Depends(get_session)):
    # 联表查询:用户表 + 部门表,通过外键关联
    stmt = select(User,Department).join(Department,User.department_id == Department.id).where(Department.name == name)
    result = await session.execute(stmt)
    user_list = result.all()

    # 组装数据返回给前端
    res = []
    for user, dept in user_list:
        res.append({
            "id": user.id, "name": user.name, "department_name": dept.name
        })
    return {"code": 200, "data": res}

四、总结

  1. 全流程核心:导入依赖 → 配置数据库 → 定义表 → 写依赖 → 写CRUD接口
  2. 增删改查规则
    • 查询:Select + execute + 获取结果
    • 新增:创建对象 + session.add()
    • 修改:查询对象 + 覆盖属性
    • 删除:Delete + 条件 + 执行
  3. 异步关键 :所有数据库操作必须加 await,否则会报错
  4. 依赖项作用 :自动帮你提交、回滚、关闭连接,不用手动管理
相关推荐
人道领域2 小时前
【黑马点评日记】:用户签到功能详解——从Bitmap入门到避坑指南
java·数据库·redis·后端
Vect__2 小时前
MySQL初识和基础操作
数据库·mysql
zhaoyong2223 小时前
如何在 MySQL 中实现基于全字段唯一性的重复行计数更新
jvm·数据库·python
X56613 小时前
为什么宝塔面板网站无法正常连接外部远程数据库_检查服务器安全组放行端口并开启IP授权
jvm·数据库·python
woxihuan1234563 小时前
C#怎么使用CancellationToken C#如何用取消令牌优雅地取消异步任务和长时间操作【进阶】
jvm·数据库·python
yexuhgu3 小时前
MySQL主从复制支持跨版本吗_不同版本间同步的注意事项
jvm·数据库·python
woxihuan1234563 小时前
CSS怎样调整弹性项目排列顺序_使用order属性轻松控制DOM显示顺序
jvm·数据库·python
m0_748554813 小时前
golang如何实现数据去重处理_golang数据去重处理实现步骤
jvm·数据库·python
神明9313 小时前
mysql索引排序规则设置方法_mysqlCollation对索引影响
jvm·数据库·python