惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
Malwarebytes
Malwarebytes
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cybersecurity and Infrastructure Security Agency CISA
F
Future of Privacy Forum
C
Cisco Blogs
T
The Exploit Database - CXSecurity.com
A
Arctic Wolf
S
Securelist
K
Kaspersky official blog
S
Schneier on Security
T
ThreatConnect
T
Tenable Blog
Spread Privacy
Spread Privacy
T
True Tiger Recordings
AWS News Blog
AWS News Blog
F
Fox-IT International blog
量子位
T
Threatpost
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
Cisco Talos Blog
Cisco Talos Blog
GbyAI
GbyAI
宝玉的分享
宝玉的分享
腾讯CDC
G
Google Developers Blog
aimingoo的专栏
aimingoo的专栏
Cyberwarzone
Cyberwarzone
有赞技术团队
有赞技术团队
S
SegmentFault 最新的问题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
U
Unit 42
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
The Register - Security
The Register - Security
MyScale Blog
MyScale Blog
小众软件
小众软件
A
About on SuperTechFans
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
博客园 - 三生石上(FineUI控件)
美团技术团队
Google Online Security Blog
Google Online Security Blog
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog

博客园_首页

聊一聊 MES系统如何实现多种标签打印并支持不同打印机 2026第四届LitCTF网络安全挑战赛Pwn的wp 断尺问题:戴德金分割现实悖论 给句子做个“语义审计”:从词向量到句子向量的方法论 当AI“卡壳”在生产环境:MCP Server 如何帮我们破局 ofdkit-harmony 0.2.0 发布:鸿蒙原生 OFD 阅读库,已上架 ohpm 有了AI测试工具,还需要掌握Playwright、Pytest、Selenium这些框架吗? 组织转型实录——我把传统研发团队改成AI驱动,踩了无数坑 为什么 AI Coding 难进生产环境?深入了解 Everything-Claude-Code ! 到底 TMD 用哪个: npm, pnpm, Yarn, Bun, Deno? 傻瓜, 当然用 npm 啦 上周热点回顾(5.18-5.24) [对比学习LangChain和MAF-04]针对消息的设计 TrueAsync Server 为 PHP 带来了原生的高性能 HTTP 服务器 规则漂移 帆软市场部为什么能成为高人效增长系统? 22. LangChain LCEL,用 | 串联AI的魔法语言 - 老陈说编程 完整学习LLM(二):大模型到底是什么 洛谷-P11942 [KTSC 2025] 重塑矩阵 题解 哈哈哈哈哈打不过我吧,没有办法我(vllm)就是这么强大! Hermes Edu Skills 从 170 到 188:一次中文教育 Agent Skill Pack 的工程化升级 一个外行,半年搞定机械臂:我的从0到1踩坑实录 新写了个直播录制工具,可录制抖音快手斗鱼直播 15天学会AI应用开发(一)搭建AI大模型应用开发环境 Childhood,23款童年卡牌游戏复刻 Github Copilot配置GPT5.5报错:'temperature' does not support 0.1 with this model. Only the default (1) value is supported. - Eric zhou 单曲循环 ClassIn 在 Linux 下无法播放音频 把 TeXstudio / LaTeX 工程交给 AI:texstudio-mcp 功能详解 .NET 8 Web开发入门(六):Blazor 全栈开发——告别 JavaScript 焦虑 别让 LLM 写文件:一套 Agent 进度跟踪的工程化范式 - BurningFish Qt Bridges for C# 深度技术解析 Multus 多网卡方案:IPVLAN 模式 被流量逼出来的架构:从一台服务器到云原生的 17 次蜕变 —— 集群、缓存、MQ、微服务、Docker、K8S 的前世今生 Claude Code安装全流程 Windows保姆级教程 awk 命令练习(从入门到进阶) Java + Spring实现Hermes Agent之龙虾、Skills、Mcp和沙箱代码执行环境思路 轨迹的蓝图:方程求解与交点计算 Agent新技术分享-Forge论文已被ACM接受 PowerMem 记忆系统的遗忘设计,从神经元到代码工程 我用了FastApiAdmin后,连夜把踩过的坑都整理出来了 一个程序员眼中的 AI 核心概念,讲透 LLM 、Agent 、MCP 、Skill 、RAG... 网络安全在线就能打的内网靶场推荐 & Dawn Breaker 单域靶场 WP CTF 中如何用提示词发挥大模型的最大实力:从聊天助手到大手子 PyTorch KernelAgent 源码解读 ---(6)--- Composer 高光谱拼接算法(一)扫推式成像和航带拼接算法 一文看懂fofa常用语法,告别混淆,精准打击! 从零搭建量化投资系统:用 Qlib 一行代码搞定均线分析 企业 AI 落地,第一件事不是买模型,而是建好企业知识库 如何在Oracle Agent Factory中配置国内厂商的LLM? Codex 换模型太麻烦?这个开源桌面工具帮你一键切换 Avalonia中的动画 2026软考|十大管理超全通俗笔记,备考闭眼记! rv1126b内置phy接hub交换机芯片 React 可拖拽列宽 + 点击行选中 ProTable 封装笔记 五大实锤证据:AI不会终结低代码,只会倒逼技术进化 【硬核脑洞】16位实模式最后的疯狂:我们能否在 640KB 常规内存里手搓一个 MD 模拟器? 基于.Net的NetCoreKevin框架中AgentFramework实现AI智能体Skill和工具动态管理和加载 PostgreSQL 高可用集群 patroni 自动故障转移测试 自己使用C++开发的仿OpenClaw、Hermes智能体工具 记一次 .NET 某集群管理软件 内存暴涨分析 StarBlog番外(5) 从1.6到1.10,基于Avalonia AOT 开发的 Publisher 半年进化之路 Anthropic 把 SOC 误报率从 33% 砍到 7%,真正在干活的不是 Claude SM2演示所有 PEM 功能(生成、加解密、签名/验签) 用 Solon AI 从零构建 MCP 工具服务:让 AI Agent 拥有真实世界的能力 完整学习LLM(一):为什么我要系统学习大模型 Agent Harness Runtime 架构深度解析:工具循环、状态外置与长程任务调度 [对比学习LangChain和MAF-03]完全不同的Agent设计哲学 毫不夸张地说,这将是目前最全的AI测试教程!测试必看! AI Coding 为什么选择 TUI ,前端的新机会在哪里? 无需安装cc switch,10行命令帮你配置Claude Code+deepseek Context Engineering 到 Harness Engineering —— 大模型时代软件工程的新范式 OpenClaw.NET 兼容性目录指南(Compatibility Catalog) Nginx 上游健康检查插件 nginx-healthcheck-module 三角形数 AScript异步执行与await关键字 - rockey627 Vector Quantization for Recommendation 笔记 21. “|”不只是按位或,90%的人不知道 这 3 年做教育相关项目,我把一些经验整理成了一个开源 Agent Skills 项目 2026 西安本土 GEO 测评:灵怡云凭差异化站稳第一梯队 PortSwigger SQL注入LAB7 & LAB8 & LAB9 Splay 学习笔记 这款爆款激光粒度仪凭何全球狂销5000台?揭秘百特Bettersize2600“常青树”背后的硬核实力 十分钟学习 TypeScript 【学习笔记】《Python编程 从入门到实践》第1章学习笔记:Python环境搭建与Hello World(完整版) 初试 vibe coding:Tauri + React + Rust 构建的 windows 本地番茄钟 从 Vibecoding 入门,到 Agent 差点入土 IDEA Maven 手动替换第三方Jar包完整教程 填充与积累:积分与面积的可视化 告别 Django Admin!这个 NodeJS 全栈框架让你在 DTO 中直接配置 Table/Form 渲染 重建 AI 认知第 1 篇:基础认知——一张地图看懂 AI Landscape VAPD AgentKit:可组合 Agent 前端通用库实践 SolonCode v2026.5.21 发布,Web 能看项目,IM 能找队友 从 LangGraph 回到 Model-Tool Loop:更聪明的模型,正在让 Agent 架构重新变简单 从人工同步到自动闭环:跨 Java/.NET 代码转换工具的工程化实践 你的显卡能跑多少算子?用 55 个检查项,给 PyTorch GPU 环境做一次冒烟测试 Claude Code 快速开始 2分钟搞定全网巡检:一个脚本+五大必备 Python 库,让你一天干别人一周的活 最近面完 30 个想转 AI 测试的人,我麻了:80% 都踩了这 4 个坑! 4.3、多体交叉存储器、Cache的基本原理、相联存储器、 Cache地址映射与变换方法 简译项目的项目落地
给 FastApiAdmin 加个“会议纪要”模块,我把后端二次开发的坑踩了个遍
一名程序媛呀 · 2026-05-25 · via 博客园_首页

😫 先吐个槽:项目跑起来了,但要加个功能模块,从哪下手?

上次我们终于把 FastapiAdmin 跑起来了,界面真不错,RBAC、菜单管理、日志监控一应俱全。心想这得省多少事啊。

但接下来需求来了:“加个会议纪要模块呗,能增删改查就行。”

你盯着文件夹看了半小时,根本不知道第一行代码该写在哪

最后我也是硬着头皮翻了N个源码文件,才摸清它的“脾气”。

📌 本文能帮你解决什么

✅ 看懂 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 这条链走顺了,后面加再多的模块都不怕。

但最大的坑也恰恰是——你千万别想跳过任何一个文件,少写一个 crud,把逻辑全扔 controller 里,后期维护起来那叫一个酸爽。

建议动手前,把 portal 模块里的五个文件从头到尾读一遍,心里有数了再开工。这里就别学我第一次上来就复制粘贴改改改,结果路径全错,debug 的时间比重新写都长😅。


💬 如果你也正在用 FastapiAdmin 搞二次开发,或者卡在某一步进行不下去,留言说说你的场景。点赞收藏加关注,我们后续接着聊聊其他FastAPI开发中的那些经验技巧与避坑指南~