尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

给 FastApiAdmin 加个“会议纪要”模块,我把后端二次开发的坑踩了个遍

给 FastApiAdmin 加个“会议纪要”模块,我把后端二次开发的坑踩了个遍
📅 发布时间:2026/6/29 23:37:25

本文能帮你解决什么

✅ 看懂 FastapiAdmin 后端的真实目录结构(和你想的不一样)

✅ 手把手新增一个完整的业务模块(model → schema → crud → service → controller)

✅ 避开路由注册、权限集成和前端联调的深坑

🧭 主要内容脉络

真实项目结构一览

➡️ 二次开发标准流程

➡️ 实战:增加“会议纪要”模块

➡️ 常见翻车现场与避坑指南

1. 先搞懂真实的项目结构,不然代码都不知道放哪

我当初 git clone 下来,看到的是这样的:

FastapiAdmin/ ├── backend/ # 后端工程,我们的主战场 │ └── app/ │ ├── core/ # 核心工具库 │ ├── config/ # Settings │ ├── utils/ # 通用工具类 │ ├── scripts/# 启动脚本 │ ├── plugin/ # 动态路由 │ └── api/ # 静态路由 │ └── v1/ │ ├── module_system/ │ ├── module_monitor/ │ ├── module_common/ │ ├── module_application/ │ └── portal/ # 一个完整的模块示例 │ ├── controller.py # 路由与请求处理 │ ├── crud.py # 数据库增删改查 │ ├── model.py # SQLAlchemy 模型 │ ├── schema.py # Pydantic 校验 │ └── service.py # 业务逻辑 ├── frontend/ # Vue3 前端工程 └── docker/ # Docker部署相关

看到没,它是把一个业务模块的所有东西打成一个小包,放在一个文件夹里,跟常见的那种 models/ apis/ services/ 分开平铺的结构完全不同。

你可能会问:“那我要新增一个模块怎么办?”照着 portal 复制一份,改吧改吧就行了,后面我一步步说。

2. 二次开发的标准流程:五个文件,一个都不能少

捋一下每个文件的职责,心里先有个谱:

🔹model.py— 定义数据库表结构,就是 SQLAlchemy 的模型类。

🔹schema.py— 接口的请求/响应数据结构,用 Pydantic 定义。

🔹crud.py— 只管和数据库打交道,增删改查全都放这里。

🔹service.py— 业务逻辑层,比如创建纪要前要校验会议时间是否冲突。

🔹controller.py— API 路由,接收请求、调 service、返回响应。

这个分法很干净,维护起来特别舒服。我一开始还想把逻辑全部塞到 controller 里,后来改需求改到崩溃,千万别学我当初偷懒。

当然,说是一个都不能少,如果你只是个简单的接口响应返回,只有一个 controller 也是Ok的!

3. 实战演示:手把手增加“会议纪要”模块

📋 需求:

增删改查会议纪要,字段:标题、参会人员、纪要内容、会议日期。

🔹 第1步:新建模块文件夹

在 module_application 下复制 portal 文件夹,重命名为 meeting,里面原有文件清空,咱们从头写。

🔹 第2步:写 model.py

from sqlalchemy import Column, Integer, String, Date, Text from app.core.base_model import ModelMixin, UserMixin # 注意这个导入路径,根据实际情况调整 class MeetingMinutes(ModelMixin, UserMixin): __tablename__ = "meeting_minutes" title = Column(String(200), nullable=False, comment="会议标题") attendees = Column(String(500), nullable=False, comment="参会人员") content = Column(Text, nullable=True, comment="纪要内容") meeting_date = Column(Date, nullable=False, comment="会议日期")

这里有个坑:一定要继承项目自己的 base_model,它把 id、create_time 这些通用字段全封装好了,别自己再定义一遍,不然字段冲突搞得你怀疑人生。

🔹 第3步:写 schema.py

from app.core.base_schema import BaseSchema from datetime import date class MeetingCreate(BaseSchema): title: str attendees: str content: str | None = None meeting_date: date class MeetingUpdate(MeetingCreate): pass class MeetingOut(MeetingCreate): id: int create_time: str class Config: from_attributes = True

🔹 第4步:写 crud.py

from app.core.base_crud import CRUDBase from .model import MeetingMinutes from .schema import MeetingCreate, MeetingUpdate, MeetingOut class MeetingCRUD(CRUDBase[MeetingMinutes, MeetingCreate, MeetingUpdate]): def __init__(self, auth: AuthSchema) -> None: """ 初始化CRUD数据层,在CRUDBase中已封装了数据库的常用操作 """ super().__init__(model=MeetingMinutes) async def get_list( self, search: dict | None = None, order_by: list[dict] | None = None, preload: list[str] | None = None, ) -> Sequence[MeetingMinutes]: """ 列表查询 参数: - search (dict | None): 查询参数 - order_by (list[dict] | None): 排序参数 - preload (list[str] | None): 预加载关系,未提供时使用模型默认项 返回: - Sequence[MeetingMinutes]: 模型实例序列 """ return await self.list(search=search, order_by=order_by, preload=preload) async def create(self, data: MeetingCreate) -> MeetingMinutes | None: return await self.create(data=data) async def update(self, id: int, data: MeetingUpdate) -> MeetingMinutes | None: return await self.update(id=id, data=data)

这要要注意:如果遇到要操作数据库,先去 CRUDBase 里面看看有没有已经封装好的方法,如果有,就不要再造轮子了,直接传参调用即可!

🔹 第5步:写 service.py

from .crud import MeetingCRUD from .schema import MeetingCreate, MeetingUpdate, MeetingOut class MeetingService: @classmethod async def create_meeting(cls, data: MeetingCreate): # 这里可以加业务校验,比如会议时间不能早于今天 return await MeetingCRUD.create(data=data) @classmethod async def update_meeting(cls, meeting_id: int, data: MeetingUpdate): return await MeetingCRUD.update(id=meeting_id, data=data)

🔹 第6步:写 controller.py

from fastapi import APIRouter from .service import MeetingService from .schema import MeetingCreate, MeetingUpdate, MeetingOut from app.common.response import ResponseSchema, SuccessResponse MeetingRouter = APIRouter(route_class=OperationLogRoute, prefix="/meeting", tags=["会议纪要"]) @MeetingRouter.post("/", response_model=ResponseSchema[MeetingOut]) async def create_meeting(data: MeetingCreate): result_dict = await MeetingService.create_metting(data=data) log.info(f"创建成功: {result_dict.get('title')}") return SuccessResponse(data=result_dict, msg="创建成功")

🔹 第7步:注册路由(最容易漏!)

去 module_application 下的初始化包文件 __init_.py 里,加上:

from .metting.controller import MettingRouter application_router.include_router(MettingRouter)

我当初写好 controller 启动服务,结果 404,查了半天才发现路由压根没注册。

但不知道你有没有注意到项目目录结构里有个plugin目录,我在 scripts/init_app.py 里的 register_routers() 方法里看到了这句代码:

# 先将动态路由注册到应用,使用速率限制器 from app.core.discover import get_dynamic_router # 获取动态路由实例 app.include_router( router=get_dynamic_router(), dependencies=[Depends(RateLimiter(times=5, seconds=10))], )

进入方法里面看细节,发现如果把整个自定义应用包放到 plugin 目录里,在初始化应用时,会自动查找包里的 controller 里的 Router 定义并自动载入到应用中,这妥妥的插件化开发呀!

4. 常见翻车现场与避坑指南

🔴数据库迁移别手动改表:FastapiAdmin 用了 Alembic,写完 model 记得跑 uv run main.py revision --env=dev,不然上线后表结构对不上,哭都来不及。

🔴权限校验别忘加:新模块接口默认不挂权限,得去 RBAC 菜单管理里配上,否则用户连 403 都报不出来,直接 404 让你找半天。

🔴前端菜单要手动配:后端只管接口,左侧菜单栏的入口得去前端菜单管理页面手动添加,不然数据能查但用户找不到入口,还以为你没做。

5. 我的血泪总结

FastapiAdmin 这种全栈脚手架,最大的价值不是代码多厉害,而是它逼着你按一套清晰的套路出牌。model → schema → crud → service → controller 这条链走顺了,后面加再多的模块都不怕。

相关新闻

  • TAS5756M数字音频放大器:BD调制、零检测与miniDSP实战解析
  • DownKyi视频管理方案:解决B站内容本地化存储的技术工作流
  • C++实现Diffie-Hellman密钥交换:从数学原理到代码实战

最新新闻

  • 【HarmonyOS/OpenHarmony】创新体验:从应用入口到页面加载理解全场景应用基础链路
  • Steam成就自由掌控:告别无法完成的游戏挑战
  • 全平台Chrome配置SSLKEYLOGFILE与Wireshark解密HTTPS流量实战指南
  • 2026在线去除本地视频水印工具推荐!免费无水印导出、安全无需下载电脑端
  • iTrustee Client安全认证机制:CA认证与TEE通信的7个安全层级详解
  • 北京IT培训机构有哪些:深度解析北京IT职业教育市场现状

日新闻

  • 【计算机毕业设计案例】基于 Spring Boot+Vue 的电影售票系统设计与实现 前后端分离架构下影院在线购票管理平台(程序+文档+讲解+定制)
  • 到底 TMD 用哪个: npm, pnpm, Yarn, Bun, Deno? 傻瓜, 当然用 npm 啦
  • Google限制Meta使用Gemini模型 凸显AI授权竞争白热化

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号