FastAPI+uv+Jinja2+Nuitka 通用Web桌面框架搭建教程|从零搭建可打包迭代的Python开发底座

给大家分享一套通用、可迭代、轻量化 Python Web 桌面开发框架 完整落地教程,主打无业务绑定、高复用、可自由拓展 。基于 uv+FastAPI+Jinja2 搭建轻量化Web开发底座,无需前端工程、零复杂配置,支持本地Web服务运行,最终通过 Nuitka 编译为单文件EXE桌面程序,是Python小型Web工具、本地应用开发的通用最优框架方案

本文全程聚焦框架集成、环境配置、工程规范、打包部署,不绑定具体业务功能,搭建完成后可自由拓展各类办公、工具、数据处理业务,新手可直接复刻复用。

一、项目介绍

本项目是一套标准化、模块化、可长期迭代 的 Python 通用Web桌面开发框架,摒弃复杂前后端分离架构,采用 FastAPI 后端服务 +Jinja2 服务端模板渲染 一体化模式,无需Vue/React前端工程,低门槛快速开发本地Web应用。

核心定位:轻量化Python Web桌面开发通用底座

核心优势:零前端工程、结构分层清晰、环境纯净隔离、支持热更新调试、一键打包EXE、可无限拓展业务

适用场景:个人工具开发、小型本地Web应用、私有化轻量服务、小型团队快速迭代项目

二、技术选型

(一)核心技术栈

所有技术组件各司其职,标准化集成,无冗余依赖,适配轻量化桌面Web框架开发:

  • 环境管理: **uv,**Rust编写的高速包管理+虚拟环境工具,替代传统pip/venv,实现项目依赖隔离、极速安装、统一环境管理,解决多项目环境冲突问题
  • Web 框架: **FastAPI,**高性能异步Web后端框架,作为框架核心服务载体,支撑路由分发、请求处理、业务拓展,性能优异、代码规范简洁
  • 模板引擎: **Jinja2,**框架核心渲染组件,实现后端服务端渲染(SSR),支持后端动态变量传参、动态页面渲染,无需独立前端项目
  • 文件处理依赖: **python-multipart,**通用文件上传依赖,为框架预留文件上传、批量处理拓展能力
  • Web 服务器: **uvicorn,**ASGI异步服务器,FastAPI专属运行载体,负责端口监听、服务启动、请求调度,保障框架稳定运行
  • 打包工具: **Nuitka,**Python高级编译打包工具,将完整框架编译为原生单文件EXE,脱离Python环境直接运行,适配桌面分发需求
  • 前端 UI 框架 :本地部署 Bootstrap 5.3.8 布局框架 + Bootstrap Icons 1.13.1 图标库,采用Jinja2模板继承架构,实现统一后台布局、主题切换、侧边栏菜单、插槽拓展,全程离线可用,无网络依赖

(二)开发与运行环境

  • 开发工具:PyCharm
  • 系统环境:Windows 10 / Windows 11
  • Python版本:3.10+ 稳定版本
  • 环境特性:全自动环境隔离,多项目依赖互不干扰,开箱即用

三、开发规范

框架全程遵循标准化开发规范,统一代码风格、目录结构,方便后期迭代、业务拓展、团队协作:

  • 项目文件夹命名:中划线,符合开源项目通用规范
  • 代码包命名:下划线,严格遵循Python官方命名规范
  • 业务逻辑、路由管理、页面渲染严格分层解耦,结构清晰
  • 统一使用 uv 管理虚拟环境与第三方依赖,统一项目构建标准
  • 无需手动配置环境变量,全自动初始化开发环境

四、搭建框架

(一)初始化项目

打开 PyCharm → 新建项目,自定义项目名称,使用 PyCharm 默认虚拟环境初始化空白项目。

(二) 环境依赖

在PyCharm终端执行以下命令,完成环境初始化、工具安装、框架依赖批量配置:

bash 复制代码
# 安装uv环境管理工具
python -m pip install uv -i https://mirrors.aliyun.com/pypi/simple/

# 验证uv安装成功
python -m uv --version

# 初始化空白项目配置文件
python -m uv init --bare

# 安装框架全套核心依赖
python -m uv add fastapi uvicorn jinja2 python-multipart nuitka

(三)目录结构

搭建可复用的分层目录结构,区分服务配置、路由、模板、业务模块,适配所有同类Web项目开发:

bash 复制代码
project-name/
├── main.py # 项目全局统一启动入口
├── project_name/
│   ├── __init__.py
│   ├── app.py              # 项目核心服务入口
│   ├── api/                   # api目录
│   ├── service/            # 业务逻辑
│   └── web/
│       ├── static/         # 本地静态资源目录
│       │   ├── lib/
│       │   │   ├── bootstrap/v5.3.8/
│       │   │   └── bootstrap-icons/v1.13.1/
│       │   ├── css/
│       │   │   └── global.css  # 全局样式
│       │   └── js/
│       │       ├── main.js
│       │       └── pdf/
│       └── templates/      # Jinja2模板目录
│           ├── layout/
│           │   └── main.html   # 全局母版布局
│           ├── pdf/
│           │   └──pdf_merge.html
│           │── error/
│                └── 404.html
│           
├── pyproject.toml          # uv依赖配置文件
└── README.md

五、核心代码集成

以下为通用无业务框架源码,完成FastAPI、Jinja2、静态资源、UI组件的完整集成,可直接复用至任意项目。

(一)服务配置 app.py

实现FastAPI初始化、Jinja2模板引擎挂载、静态资源配置、基础路由,是整个框架的核心载体:

python 复制代码
import sys

from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.responses import JSONResponse
from pathlib import Path

from wisear_tools.api.v1.pdf_api import router as pdf_router


def create_app():
    app = FastAPI(title="通用工具箱")
    if getattr(sys, 'frozen', False):
        # EXE 运行时:取 exe 所在目录
        PROJECT_ROOT = Path(sys.executable).parent
    else:
        # 开发运行时:保持你原来的路径逻辑
        PROJECT_ROOT = Path(__file__).parent.parent

    # 静态资源 & 模板目录
    web_dir = PROJECT_ROOT / "wisear_tools" / "web"
    app.mount("/static", StaticFiles(directory=web_dir / "static"), name="static")
    templates = Jinja2Templates(directory=web_dir / "templates")

    # 首页&PDF合并页面路由
    @app.get("/")
    @app.get("/pdf/merge")
    async def pdf_merge_page(request: Request):
        return templates.TemplateResponse(
            name="pdf/merge.html",
            request=request,
            context={"title": "PDF合并", "active": "pdf_merge"}
        )

    # 业务接口路由
    app.include_router(pdf_router, prefix="/api/v1")

    # 自定义404异常处理
    @app.exception_handler(404)
    async def custom_404(request: Request, exc):
        req_path = request.url.path
        # API路径返回JSON格式404
        if req_path.startswith("/api/"):
            return JSONResponse(
                status_code=404,
                content={"code": 404, "msg": "请求接口不存在", "data": None}
            )
        # 页面路径返回布局内404视图
        return templates.TemplateResponse(
            name="error/404.html",
            request=request,
            context={"title": "页面不存在", "active": ""}
        )

    return app


app = create_app()

(二)启动入口 main.py

全局统一启动文件,适配开发热更新Nuitka打包生产环境,自动区分环境、关闭打包热更新,控制台友好提示:

python 复制代码
import sys
import uvicorn

HOST = "127.0.0.1"
PORT = 8000
APP_MODULE = "wisear_tools.app:app"


def is_frozen() -> bool:
    return getattr(sys, "frozen", False)


if __name__ == "__main__":
    print(f"✅ 服务已启动:http://{HOST}:{PORT}")
    print(f"👉 请复制上面地址到浏览器打开")
    uvicorn.run(
        APP_MODULE,
        host=HOST,
        port=PORT,
        reload=not is_frozen(),
        workers=1
    )

本框架采用Jinja2模板继承架构 ,统一全局布局,所有页面复用侧边栏、顶部导航、主题切换、面包屑等通用结构。前端基于 Bootstrap 5.3.8 + Bootstrap Icons 1.13.1 构建,全部使用**本地静态资源部署**,无CDN依赖,打包后100%离线可用。

核心特性:自适应布局、亮色/暗色主题切换、侧边栏折叠、全屏、刷新、多级菜单、模板插槽拓展。

(三)通用布局页面

本框架采用Jinja2 模板继承架构 ,统一全局布局,所有页面复用侧边栏、顶部导航、主题切换、面包屑等通用结构。前端基于 Bootstrap 5.3.8 + Bootstrap Icons 1.13.1 构建,全部使用**本地静态资源部署**,无CDN依赖,打包后100%离线可用。

核心特性:自适应布局、亮色/暗色主题切换、侧边栏折叠、全屏、刷新、多级菜单、模板插槽拓展。

**1.**核心布局页

html 复制代码
html
<!DOCTYPE html>
<html lang="zh-CN" data-bs-theme="light">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}通用工具箱{% endblock %}</title>
    <!-- 本地 Bootstrap 5.3.8 -->
    <link rel="stylesheet" href="/static/lib/bootstrap/v5.3.8/css/bootstrap.min.css">
    <!-- 本地 Bootstrap Icons 1.13.1 -->
    <link rel="stylesheet" href="/static/lib/bootstrap-icons/v1.13.1/bootstrap-icons.css">
    <!-- 全局自定义样式 -->
    <link rel="stylesheet" href="/static/css/global.css">
    {% block css %}{% endblock %}
</head>
<body>
<div class="layout-wrapper">
    <!-- 侧边栏菜单 -->
    <aside class="sidebar" id="sidebar">
        <div class="sidebar-header">
            <div class="sidebar-logo">
                <i class="bi bi-box-seam"></i>
                <span class="logo-text">ToolBox</span>
            </div>
        </div>
        <div class="sidebar-menu">
            <!-- 可无限拓展菜单模块 -->
            <div class="menu-item has-child">
                <i class="bi bi-file-pdf-fill"></i>
                <span class="menu-text">PDF工具</span>
                <i class="bi bi-chevron-down menu-arrow"></i>
            </div>
            <div class="sub-menu">
                <a href="/pdf/merge" class="menu-item">
                    <i class="bi bi-front"></i>
                    <span class="menu-text">PDF合并</span>
                </a>
                <a href="/pdf/split" class="menu-item">
                    <i class="bi bi-scissors"></i>
                    <span class="menu-text">PDF拆分</span>
                </a>
                <a href="/pdf/compress" class="menu-item">
                    <i class="bi bi-file-zip"></i>
                    <span class="menu-text">PDF压缩</span>
                </a>
            </div>
            <div class="menu-item has-child">
                <i class="bi bi-file-text"></i>
                <span class="menu-text">文档工具</span>
                <i class="bi bi-chevron-down menu-arrow"></i>
            </div>
        </div>
    </aside>

    <!-- 主内容区域 -->
    <main class="content-container">
        <header class="content-header">
            <div class="header-left">
                <button id="toggleBtn" class="btn btn-sm btn-dark me-3">
                    <i class="bi bi-list"></i>
                </button>
                <h6 class="mb-0">通用工具箱</h6>
            </div>
            <div class="header-right">
                <button id="btnRefresh" class="btn btn-sm btn-dark" title="刷新页面">
                    <i class="bi bi-arrow-clockwise"></i>
                </button>
                <button id="btnFullscreen" class="btn btn-sm btn-dark" title="全屏切换">
                    <i class="bi bi-arrows-fullscreen"></i>
                </button>
                <button id="btnTheme" class="btn btn-sm btn-dark" title="主题切换">
                    <i class="bi bi-moon-stars"></i>
                </button>
            </div>
        </header>
        <div class="content-body">
            <div class="container-fluid">
                <nav aria-label="breadcrumb" class="mb-4">
                    <ol class="breadcrumb mb-0">
                        <li class="breadcrumb-item"><a href="/">首页</a></li>
                        <li class="breadcrumb-item active" id="pageTitle">功能页面</li>
                    </ol>
                </nav>
                <!-- 子页面内容插槽 -->
                {% block content %}{% endblock %}
            </div>
        </div>
    </main>
</div>

<script src="/static/js/main.js"></script>
{% block script %}{% endblock %}
</body>
</html>

**2.**功能子页面模板

html 复制代码
{% extends "layout/main.html" %}
{% block title %}PDF合并 - 文档工具箱{% endblock %}

{% block content %}
<div class="row g-4">
    <!-- 左侧配置区:完全适配主题的卡片 -->
    <div class="col-lg-4">
        <div class="card h-100 shadow-sm">
            <!-- 卡片头使用 Bootstrap 主题默认的浅色/深色背景 -->
            <div class="card-header">
                <h6 class="mb-0"><i class="bi bi-sliders me-2"></i>合并配置</h6>
            </div>
            <div class="card-body">
                <p class="text-muted small mb-4">支持上传多个 PDF 文件,可调整顺序后一键合并导出。</p>

                <div class="mb-3">
                    <label class="form-label fw-medium">选择 PDF 文件</label>
                    <!-- form-control 会自动适配主题背景/边框 -->
                    <input class="form-control" type="file" id="fileInput" multiple accept=".pdf">
                </div>

                <div class="mb-4">
                    <label class="form-label fw-medium">导出文件名称</label>
                    <input class="form-control" type="text" id="outputName" value="合并文档">
                </div>

                <button class="btn btn-primary w-100 py-2 fw-medium" id="mergeBtn">
                    <i class="bi bi-check-circle-fill me-2"></i>开始合并
                </button>

                <div id="tips" class="mt-3 text-center small"></div>
            </div>
        </div>
    </div>

    <!-- 右侧文件列表:完全适配主题的卡片 -->
    <div class="col-lg-8">
        <div class="card h-100 shadow-sm">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h6 class="mb-0"><i class="bi bi-file-earmark-pdf me-2"></i>已上传文件</h6>
                <span class="badge bg-primary" id="fileCount">0 个文件</span>
            </div>
            <div class="card-body p-0 overflow-auto" style="max-height: calc(100vh - 280px);">
                <div id="fileList" class="list-group list-group-flush">
                    <div class="list-group-item text-center text-muted py-4">
                        <i class="bi bi-file-earmark-fill d-block mb-2 fs-4"></i>
                        暂无上传文件
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block script %}
<script src="/static/js/pdf/merge.js"></script>
{% endblock %}

**3++.++**404 通用兜底页面

html 复制代码
{% extends "layout/main.html" %}
{% block title %}页面不存在{% endblock %}

{% block content %}
<div class="d-flex flex-column align-items-center justify-content-center h-100">
    <h1 class="display-1 text-primary">404</h1>
    <h4 class="my-3">访问的页面不存在</h4>
    <a href="/" class="btn btn-primary px-4 py-2">返回首页</a>
</div>
{% endblock %}

六、启动测试

(一)开发环境启动命令

终端执行标准化启动命令,开启热更新,支持开发过程实时调试:

bash 复制代码
python -m uv run uvicorn project_name.app:app --host 127.0.0.1 --port 8000 --reload

(二)框架访问验证

启动成功后,浏览器访问:http://127.0.0.1:8000

页面正常渲染、后端动态变量展示正常、UI样式适配完成,代表整套框架集成成功,可自由拓展业务功能。

**七、**Nuitka 框架一键打包配置

框架开发完成后,可通过Nuitka一键打包为独立EXE程序,脱离Python环境运行,适配桌面分发场景,打包脚本通用可复用:

(一)一键打包脚本 build.bat

bash 复制代码
@echo off
python -m uv run nuitka ^
--onefile ^
--windows-console-mode=force ^
--include-package=project_name ^
--include-data-dir=project_name/web/static=project_name/web/static ^
--include-data-dir=project_name/web/templates=project_name/web/templates ^
--output-dir=dist ^
--output-filename=web-framework.exe ^
main.py
pause

**(二)**打包核心参数说明

  • --onefile:打包为单文件EXE,简洁易分发
  • --windows-console-mode=force:保留控制台日志,便于排查运行异常
  • --include-data-dir:强制打包模板与静态资源,解决打包后页面空白、资源丢失问题

八、框架优势

  • 技术栈轻量化:无需前端工程、无需复杂后端配置,低门槛快速搭建可用Web服务框架
  • 环境纯净可控:基于uv管理环境,依赖隔离、安装极速,杜绝环境冲突
  • 高可拓展性:分层架构清晰,可自由新增工具、业务、接口功能,适配长期迭代
  • 双场景适配:支持开发热更新调试、生产打包部署,一套框架适配全流程
  • 运行稳定:规避Nuitka打包闪退、资源丢失、浏览器弹窗失效等通用坑

九、整体总结

uv+FastAPI+Jinja2+Nuitka 是目前 Python 轻量化 Web 桌面应用 的最优通用框架方案。兼顾开发效率、运行稳定性、可打包性与可迭代性,无需复杂技术栈,以极简架构实现完整Web服务能力,适合绝大多数个人开发、小型项目、本地工具开发场景,可作为通用Python Web开发底座长期复用。

本文为通用框架实战教程,无业务绑定、可直接复刻复用,快速搭建属于自己的轻量化Python Web开发底座

相关推荐
Ulyanov3 小时前
用声明式语法重新定义Python桌面UI:QML+PySide6现代开发入门(一)
开发语言·python·算法·ui·系统仿真·雷达电子对抗仿真
❀搜不到4 小时前
Ubuntu查看指定Python程序的CPU、GPU、内存占用情况
linux·python·ubuntu
卷无止境4 小时前
用一个机器车间,研究SimPy核心概念
python
zhendianluli5 小时前
PyTorch 复杂模型转 ONNX 踩坑纪实:从 diff 到 nan_to_num 的三关突破
人工智能·pytorch·python
python在学ing5 小时前
Django框架学习笔记:从零基础到项目实战
数据库·python·django·sqlite
PAK向日葵5 小时前
从零实现 Python 虚拟机(二):S.A.A.U.S.O 的总体架构设计
c++·python
程序员小远5 小时前
系统性能指标全解析
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·性能测试
@我们的天空6 小时前
Claude Code + GLM-5 深度赋能测试:开发 8 大 Skill 构建 AI 测试助手集群
人工智能·python·测试工具·自动化·ai编程