FastAPI+SQLModel+PostgreSQL+React+Vite全栈项目文件结构说明环境搭建与初始化指南


发布者 ourjs  发布时间 1767145815981
关键字 react hooks  Python 

这篇文章是一份关于 FastAPI + SQLModel + PostgreSQL + React 全栈项目的环境搭建与初始化指南。它详细介绍了从数据库部署、后端环境配置到前端启动的整个流程,并提供了标准化的项目目录结构。

数据库环境搭建 (Database)

使用 Docker 快速部署: 配置 Docker 镜像源以加速下载。 使用docker run命令启动PostgreSQL数据库服务,并通过数据卷(Volume)实现数据持久化。 部署pgAdmin4作为可视化管理工具,并提供了访问地址和默认登录信息。 连接信息:汇总了连接 PostgreSQL 所需的主机、端口、用户名和密码。

PostgreSQL Server

docker pull postgres:alpine
docker volume create postgre-data
docker run -id --name=postgresql -v postgre-data:"/github/postgresql/data" -p 5432:5432 -e POSTGRES_PASSWORD=123456 -e LANG=C.UTF-8 postgres

PostgreSQL Client 数据库管理客户端

docker pull dpage/pgadmin4
docker run -p 8083:80 -e PGADMIN_DEFAULT_EMAIL=user@qq.com -e PGADMIN_DEFAULT_PASSWORD=123456 -d dpage/pgadmin4


## OK
主机  宿主机 IP(如 127.0.0.1)
端口  5432
用户名 postgres
密码  123456
数据库名    postgres

访问数据库管理工具: http://localhost:8083/browser/ 创建一个名为 hotel 的表

数据库连接文件

文件: core\database\db.py

from contextlib import asynccontextmanager
from sqlmodel.ext.asyncio.session import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine

SQLALCHEMY_DATABASE_URI="postgresql://postgres:123456@localhost:5432/hotel"
SQLALCHEMY_DATABASE_URI_ASYNC="postgresql+asyncpg://postgres:123456@localhost:5432/hotel"

async_engine = create_async_engine(
    SQLALCHEMY_DATABASE_URI_ASYNC,
    echo=True,
    pool_size=5,
)

# @asynccontextmanager 是 Python 标准库 contextlib 模块提供的装饰器,用于快速创建异步的上下文管理器,核心价值是:
# get_async_session() 必须是一个异步上下文管理器,
@asynccontextmanager
async def get_async_session():
    async_session = AsyncSession(async_engine, expire_on_commit=False)
    try:
        yield async_session
        await async_session.commit()
    except Exception as e:
        await async_session.rollback()
        raise e
    finally:
        await async_session.close()

后端环境配置 (Python FastAPI)

Anaconda 与 Conda 源:

可使用 Anaconda 进行 Python 环境管理,并配置了清华镜像源以加速包的安装。

虚拟环境 (venv):

使用 Python 内置的venv模块创建并激活名为corepy的虚拟环境。 使用venv创建虚拟环境:Python标准库自带,更为简洁

安装了项目核心依赖:fastapi, uvicorn, sqlmodel等。 使用venv创建虚拟环境:Python标准库自带,不可指定python版本

python -m venv corepy
corepy\Scripts\activate


pip install fastapi
pip install starlette
pip install uvicorn
pip install sqlmodel

pip freeze > requirements.txt

vscode 选择 venv 虚拟机

打开命令面板(Ctrl+Shift+P / Cmd+Shift+P); 输入「Python: Select Interpreter」(选择解释器); 选择后虚拟机 corepy 中的 python.exe

PostgreSQL 数据模型创建

与 FastAPI + SQLModel 适配性较好的数据库迁移工具主要有 Alembic(SQLAlchemy 官方配套)

安装 alembic

pip install alembic
pip install psycopg2-binary

初始化 Alembic

数据库迁移脚本放到 core/database/migrations 目录下

cd core

alembic init database/migrations

数据模型创建

这段代码是基于 SQLModel(FastAPI 生态的 ORM 工具)定义的用户数据模型,核心包含两个类:UserLogin 是用于接收前端登录请求的「数据校验模型」,UserModel 是映射数据库 user 表的「数据库模型」,既实现了请求参数校验,又完成了数据库表结构定义。

文件: core\modules\user\user_model.py

from datetime import datetime
from sqlalchemy import text
from sqlmodel import Field, SQLModel

class UserLogin(SQLModel):
    username: str | None = Field(default=None, max_length=255, min_length=4)
    password: str | None = Field(default=None, max_length=255, min_length=6)

class UserModel(UserLogin, table=True):
    __tablename__ = "user"  # Explicitly specify database table name

    id: int | None = Field(default=None, primary_key=True)
    create_at: datetime | None = Field(
        default_factory=datetime.now,
        # text() 会将其渲染为 DEFAULT CURRENT_TIMESTAMP(无引号,作为 PostgreSQL 函数执
        sa_column_kwargs={"server_default": text("CURRENT_TIMESTAMP")}
    )

配置 env.py 连接数据库

创建 target_metadata 用来创建数据库升级脚本, 所有模型都基于同一个 SQLModel.metadata,因此直接导出即可

文件: core/models/init.py

# 1. 统一导入 SQLModel(避免重复导入)
from sqlmodel import SQLModel

# 2. 导入所有分散的模型(按模块归类)
# 注意:只需导入模型类,无需导入其他内容
from user.user_model import UserModel
from reservation.reservation_model import ReservationModel

# 3. 导出 metadata(供 Alembic 使用)
# 所有模型都基于同一个 SQLModel.metadata,因此直接导出即可
target_metadata = SQLModel.metadata

修改 env.py, 将之前的 target_metadata 替换成你的版本:

from database import target_metadata
from database.db import SQLALCHEMY_DATABASE_URI

def get_url():
    return str(SQLALCHEMY_DATABASE_URI)

# 修改创建脚本, 如
url = get_url()
connectable = create_engine(get_url())

创建数据库表和迁移指令

alembic revision --autogenerate -m "Initial migration"

若有错误:

# 1. 先备份数据库(重要!)
pg_dump -U postgres -d postgres > backup.sql  # PostgreSQL 备份

# 2. 重置数据库迁移版本(清空 alembic_version 表)
alembic downgrade base  # 回滚所有迁移(会删除表,谨慎!)

# 3. 重新生成初始脚本
alembic revision --autogenerate -m "Initial migration"

# 4. 应用新脚本
alembic upgrade head

应用数据库迁移

这个指令会将之前定义的 UserModel 和 ReservationModel 模型对应的表自动升级到PostgreSQL数据库

alembic upgrade head

回滚数据库(撤销迁移)

如果创建有误,可以撤消迁移

alembic downgrade -1

FastAPI 后端

入口文件

这段代码是 FastAPI 项目的核心入口文件,作用是初始化 FastAPI 应用、注册静态文件中间件、挂载业务接口路由,同时预留了另一种静态文件托管的方案

文件: core\main.py

from fastapi import FastAPI
from middleware.static_file import StaticFile
from modules.reservation.reservation_controller import router as reservation_router
from modules.user.user_controller import router as user_router

app = FastAPI()
app.add_middleware(StaticFile)
app.include_router(reservation_router)
app.include_router(user_router)

静态文件中间件

这段代码是 FastAPI 中一个静态文件中间件(StaticFile),核心作用是让 FastAPI 后端同时接管前端静态文件(如 React/Vue 打包后的 dist 目录)的访问,还能兼容前端路由的 “history 模式”(避免刷新页面 404)。

文件: core\middleware\static_file.py

from os import path
from fastapi import Response
from fastapi.responses import FileResponse
from starlette.middleware.base import BaseHTTPMiddleware
import os
import mimetypes

static_dir = path.join(os.getcwd(), "../web/dist")

class StaticFile(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        if request.url.path.startswith("/api/"):
            return await call_next(request)

        ### path.join 跟 node.js 行为不一样, python要去除 /
        file_path = path.join(static_dir, request.url.path.lstrip('/'))
        if path.isdir(file_path):
            file_path = path.join(file_path, "index.html")

        # 目录不存在,则视为前端路由
        if path.exists(file_path):
            if path.isfile(file_path):
                content_type, _ = mimetypes.guess_type(file_path) or "application/octet-stream"
                return FileResponse(file_path, media_type = content_type)
        else:
            return FileResponse(path.join(static_dir, "index.html"), media_type="text/html; charset=utf-8")

        return Response("Not Found", status_code=404)

创建路由Controller

这段代码是 FastAPI 中用户模块的接口路由控制器,核心作用是定义用户相关的 API 接口(登录、注册、查询列表),并将接口逻辑解耦到user_service层,同时用UserLogin/UserModel做请求参数校验,是典型的 “控制器 - 服务层” 分层设计。

文件: core\modules\user\user_controller.py

from fastapi import APIRouter

from modules.user.user_service import user_list, user_signin, user_signup
from modules.user.user_model import UserLogin, UserModel

router = APIRouter(
    prefix="/api/v1/user",
    tags=["User Module"],
    responses={ 404: {"description": "User module not exist"} }
)

@router.post("/signin")
async def signin(userLogin: UserLogin):
    user = await user_signin(userLogin)
    return { "error": "" if user is not None else "User not found" }

@router.post('/signup')
async def signup(userInfo: UserModel):
    exception = await user_signup(userInfo)
    return { "error": "" if exception is None else str(exception) }

@router.get('/list')
async def list():
    try:
        users = await user_list()
        return { "result": users }
    except Exception as ex:
        return { "error": str(ex) }

创建业务服务层Service

这段代码是 FastAPI 项目中用户模块的业务服务层(user_service),核心作用是实现用户注册、登录、查询列表的核心业务逻辑,基于SQLModel操作 PostgreSQL 异步数据库,

文件: core\modules\user\user_service.py

from sqlmodel import select
from database.db import get_async_session
from modules.user.user_model import UserLogin, UserModel

async def user_signup(data: UserModel):
    async with get_async_session() as session:
         # add是同步方法,不需要await!
        session.add(data)

async def user_signin(userLogin: UserLogin):
    async with get_async_session() as session:
        statement = select(UserModel).where(
            UserModel.username == userLogin.username and UserModel.password == userLogin.password
        )
        users = await session.exec(statement)
        return users.first()

async def user_list():
    async with get_async_session() as session:
        statement = select(UserModel).order_by(UserModel.create_at)
        users = await session.exec(statement)
        return users.all()

启动后端程序

FastAPI 项目的启动命令(Windows 系统下),核心作用是先激活 Python 虚拟环境,再启动 FastAPI 的开发服务器。 用uvicorn(FastAPI 的官方服务器)启动项目,监听所有网络地址的 8000 端口,开启热重载

corepy\Scripts\activate
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

React 前端

使用 vite 创建 react 项目:

npm create vite@latest web

运行这个项目

npm run:dev

项目结构

Project tree

package  # 项目根目录
   ├── .gitignore  # Git忽略文件配置
   ├── BUILD.md  # 项目构建说明文档
   ├── core  # 后端核心目录
   │   ├── alembic.ini  # Alembic配置文件
   │   ├── database  # 数据库相关目录
   │   │   ├── db.py  # 数据库连接配置
   │   │   ├── migrations  # Alembic迁移脚本目录
   │   │   │   ├── env.py  # Alembic核心配置
   │   │   │   ├── README  # 迁移目录说明
   │   │   │   ├── script.py.mako  # 迁移脚本模板
   │   │   │   └── versions  # 迁移脚本版本目录
   │   │   └── __init__.py  # 数据库模块初始化文件
   │   ├── main.py  # FastAPI应用入口文件
   │   ├── middleware  # 中间件目录
   │   │   └── static_file.py  # 静态文件中间件
   │   ├── modules  # 业务模块目录
   │   │   ├── reservation  # 预约模块
   │   │   │   ├── reservation_controller.py  # 预约接口控制器
   │   │   │   ├── reservation_model.py  # 预约数据模型
   │   │   │   └── reservation_service.py  # 预约业务逻辑
   │   │   └── user  # 用户模块
   │   │      ├── user_controller.py  # 用户接口控制器
   │   │      ├── user_model.py  # 用户数据模型
   │   │      └── user_service.py  # 用户业务逻辑
   │   ├── requirements.txt  # 后端依赖包清单
   │   └── __init__.py  # 核心模块初始化文件
   ├── README.md  # 项目说明文档
   ├── SPEC.md  # 项目规格说明
   └── web  # 前端目录
      ├── .gitignore  # 前端Git忽略文件
      ├── .pnp.cjs  # Yarn PnP配置文件
      ├── .pnp.loader.mjs  # Yarn PnP加载器
      ├── eslint.config.js  # ESLint代码检查配置
      ├── index.html  # 前端入口HTML
      ├── package-lock.json  # npm依赖锁文件
      ├── package.json  # 前端项目配置(依赖、脚本)
      ├── public  # 静态资源目录
      │   └── vite.svg  # 示例静态资源
      ├── README.md  # 前端说明文档
      ├── src  # 前端源码目录
      │   ├── App.css  # 根组件样式
      │   ├── App.test.ts  # 根组件测试文件
      │   ├── App.tsx  # 根组件
      │   ├── assets  # 资源文件目录
      │   │   └── react.svg  # React图标
      │   ├── common  # 通用工具目录
      │   │   ├── ApiRequest.ts  # API请求封装
      │   │   └── ApiResponse.ts  # API响应封装
      │   ├── components  # 通用组件目录
      │   │   ├── DataList  # 数据列表组件
      │   │   ├── ReservationForm  # 预约表单组件
      │   │   └── SiteNav  # 站点导航组件
      │   ├── index.css  # 全局样式
      │   ├── main.tsx  # 前端入口文件
      │   ├── models  # 前端数据模型
      │   │   ├── Reservation.ts  # 预约模型
      │   │   └── User.ts  # 用户模型
      │   ├── pages  # 页面组件目录
      │   │   ├── Manage  # 管理页面
      │   │   ├── Sign  # 登录/注册页面
      │   │   └── Welcome  # 欢迎页面
      │   └── stores  # 状态管理目录
      │      └── UserStore.ts  # 用户状态管理
      ├── tsconfig.app.json  # TypeScript应用配置
      ├── tsconfig.json  # TypeScript根配置
      ├── tsconfig.node.json  # TypeScript Node配置
      └── vite.config.ts  # Vite构建配置