1. 为什么说模块化设计是企业级开发的“定海神针”?
如果你做过几个企业级的中后台项目,肯定遇到过这样的场景:项目初期,需求简单,代码写得飞快,感觉一切尽在掌握。但随着业务像滚雪球一样越滚越大,新功能不断往里塞,你会发现代码越来越难改,牵一发而动全身,加个小功能都得小心翼翼,生怕把哪个老模块搞崩了。这就是典型的“面条式”代码带来的恶果,而解决这个问题的核心钥匙,就是模块化设计。
FastAPI-Vue3-Admin 这个项目,我上手深度体验了几个月,它最打动我的地方,就是把“模块化”这个理念真正落到了实处,而不是一个空洞的口号。它不像有些框架,只是把文件按功能分个文件夹,内部还是高度耦合。这个项目从架构层面就强制要求你进行解耦,让你想写出“坏味道”的代码都难。
它的模块化具体体现在哪里呢?我举个例子你就明白了。比如你们公司要开发一个电商后台,通常会有用户、商品、订单、营销等核心模块。在 FastAPI-Vue3-Admin 里,你只需要在 backend/app/plugin/ 目录下创建几个文件夹:module_user/、module_product/、module_order/、module_promotion/。每个文件夹都是一个完全独立的王国,里面有自己专属的 controller.py(处理请求)、model.py(定义数据表)、schema.py(数据校验)、service.py(业务逻辑)和 crud.py(数据库操作)。
这种设计带来的好处是实实在在的。首先,新人上手极快。一个新同事来了,你让他负责“订单模块”,他只需要钻进 module_order 这个文件夹里研究就行,完全不用关心用户模块是怎么处理登录的,商品模块的库存是怎么扣减的。代码的边界非常清晰,极大地降低了认知负担。
其次,维护和升级变得异常轻松。当营销活动需要改版,你只需要改动 module_promotion 下的代码。只要接口契约(也就是请求和响应的数据结构)不变,其他模块完全感知不到你的改动。甚至,你可以把整个营销模块替换成另一套实现,只要保证对外提供的API不变,整个系统就能平稳运行。这种松耦合的特性,让系统具备了极强的弹性和可维护性。
最后,它天然支持团队并行开发。后端可以按模块分给不同的人,前端也可以对应地按模块划分页面。大家各司其职,通过定义好的API接口进行联调,互不干扰,开发效率能提升好几个档次。我经历过那种所有人都在改同一个大文件,天天解决合并冲突的日子,相比之下,这种模块化开发简直就是一种享受。
2. 5分钟快速上手:从零启动你的第一个模块
光说不练假把式,咱们直接动手,看看怎么用 FastAPI-Vue3-Admin 在5分钟内创建一个全新的功能模块。假设我们要给系统增加一个“新闻公告”模块,用于发布和管理公司内部通知。
首先,确保你已经按照官方文档把项目跑起来了。接下来,我们进入后端目录,开始“造轮子”。
第一步,创建模块的“家”。在 backend/app/plugin/ 目录下,新建一个文件夹,名字必须以 module_ 开头,比如 module_news。
cd backend/app/plugin/
mkdir module_news
cd module_news
第二步,在这个“家”里,创建我们功能的核心文件。我们再建一个子文件夹,比如叫 announcement,用来放公告相关的所有代码。
mkdir announcement
cd announcement
现在,我们在这个 announcement 文件夹里,创建五个核心文件。别怕,大部分内容都可以用项目自带的代码生成器来生成,这里我们先手动创建,理解其结构:
model.py:定义数据表长什么样。schema.py:定义API接口“收发货”的数据格式。crud.py:定义怎么跟数据库“对话”。service.py:处理复杂的业务逻辑。controller.py:定义API路由,处理HTTP请求。
我们先从最简单的 model.py 开始,定义一个公告的数据模型:
# backend/app/plugin/module_news/announcement/model.py
from sqlalchemy import Column, Integer, String, Text, DateTime
from app.db.base_class import Base
from datetime import datetime
class Announcement(Base):
__tablename__ = "news_announcement" # 数据库表名
id = Column(Integer, primary_key=True, index=True, comment='主键ID')
title = Column(String(255), nullable=False, comment='公告标题')
content = Column(Text, comment='公告内容')
publisher = Column(String(50), comment='发布人')
publish_time = Column(DateTime, default=datetime.now, comment='发布时间')
is_top = Column(Integer, default=0, comment='是否置顶 (0:否, 1:是)')
status = Column(Integer, default=1, comment='状态 (0:禁用, 1:启用)')
看,这就是一个标准的SQLAlchemy模型。定义了公告的标题、内容、发布人等字段。Base 是项目里定义好的基类,帮你处理好了很多底层细节。
接下来是 schema.py,它用来做数据验证。比如创建公告时,我们要求标题不能为空,内容至少10个字:
# backend/app/plugin/module_news/announcement/schema.py
from pydantic import BaseModel, Field, validator
from typing import Optional
from datetime import datetime
class AnnouncementCreate(BaseModel):
"""创建公告的请求体格式"""
title: str = Field(..., min_length=1, max_length=255, description='公告标题')
content: str = Field(..., min_length=10, description='公告内容')
is_top: Optional[int] = 0
@validator('title')
def title_not_empty(cls, v):
if not v or not v.strip():
raise ValueError('标题不能为空')
return v.strip()
class AnnouncementUpdate(BaseModel):
"""更新公告的请求体格式"""
title: Optional[str] = None
content: Optional[str] = None
is_top: Optional[int] = None
status: Optional[int] = None
class AnnouncementOut(BaseModel):
"""返回给前端的公告数据格式"""
id: int
title: str
content: str
publisher: str
publish_time: datetime
is_top: int
status: int
class Config:
from_attributes = True # 兼容ORM对象
Pydantic 模型的好处是,数据在进入你的业务逻辑之前就已经被验证和清洗过了,非法数据根本进不来,大大增强了系统的健壮性。
然后是 crud.py,这里是与数据库交互的“搬运工”:
# backend/app/plugin/module_news/announcement/crud.py
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update, delete
from typing import Optional, List
from .model import Announcement
from .schema import AnnouncementCreate, AnnouncementUpdate
class CRUDAnnouncement:
async def create(self, db: AsyncSession, *, obj_in: AnnouncementCreate, publisher: str) -> Announcement:
# 将Pydantic模型转换为数据库模型实例
db_obj = Announcement(
title=obj_in.title,
content=obj_in.content,
is_top=obj_in.is_top,
publisher=publisher
)
db.add(db_obj)
await db.commit()
await db.refresh(db_obj) # 获取创建后的完整对象,包含ID等
return db_obj
async def get(self, db: AsyncSession, id: int) -> Optional[Announcement]:
result = await db.execute(select(Announcement).where(Announcement.id == id))
return result.scalar_one_or_none()
async def get_multi(self, db: AsyncSession, *, skip: int = 0, limit: int = 100) -> List[Announcement]:
result = await db.execute(select(Announcement).offset(skip).limit(limit))
return result.scalars().all()
async def update(self, db: AsyncSession, *, db_obj: Announcement, obj_in: AnnouncementUpdate) -> Announcement:
update_data = obj_in.dict(exclude_unset=True) # 只更新提供了的字段
for field, value in update_data.items():
setattr(db_obj, field, value)
db.add(db_obj)
await db.commit()
await db.refresh(db_obj)
return db_obj
async def remove(self, db: AsyncSession, *, id: int) -> Announcement:
result = await db.execute(select(Announcement).where(Announcement.id == id))
db_obj = result.scalar_one()
await db.delete(db_obj)
await db.commit()
return db_obj
crud_announcement = CRUDAnnouncement() # 创建一个实例供其他地方调用
这里全是标准的数据库增删改查操作。注意它使用了 AsyncSession,这意味着它是异步的,能更好地利用FastAPI的异步特性,在高并发场景下表现更优。
业务逻辑层 service.py 是核心,它协调 crud 操作,并可以加入更复杂的逻辑,比如权限判断、发送通知等:
# backend/app/plugin/module_news/announcement/service.py
from sqlalchemy.ext.asyncio import AsyncSession
from typing import List, Optional
from . import crud_announcement
from .schema import AnnouncementCreate, AnnouncementUpdate, AnnouncementOut
from app.core.exceptions import CustomException
class AnnouncementService:
async def create_announcement(self, db: AsyncSession, data: AnnouncementCreate, publisher: str) -


329

被折叠的 条评论
为什么被折叠?



