2026-05-24
Python
0

目录

创建虚拟环境
项目代码创建
.env配置
控制器
路由
Flask 应用
app启动类
运行
补充

Flask是一个基于Python实现的、基于MVC设计模式的、轻量级的Web开发框架,也被称为“微框架”,因为它使用简单的核心,用扩展来增加其他功能。

Flask流行的主要原因:

  • 有非常齐全的官方文档,上手非常方便
  • 有非常好的扩展机制和第三方的扩展环境,工作中常见的软件都有对应的扩展,自己动手实现扩展也很容易
  • 微型框架的形式给了开发者更大的选择空间

现在我们从零开始搭建项目环境

创建虚拟环境

在项目根目录执行

bash
# Windows/macOS/Linux 通用 python -m venv venv

执行后,项目里会多出一个 venv 文件夹

激活虚拟环境

  • Windows(命令提示符 CMD)

    bash
    venv\Scripts\activate
  • Windows(PowerShell)

    bash
    .\venv\Scripts\Activate.ps1
  • macos/linux

    bash
    source venv/bin/activate

项目目录

|---app // 应用入口集合 | ├---__init__.py | └---http |---config // 应用配置文件 | ├---__init__.py | ├---config.py | └---default_config.py |---internal // 应用所有内部文件夹 | ├---core // LLM核心文件,集成LangChain、LLM、Embedding等非逻辑的代码 | | |---agent | | |---chain | | |---prompt | | |---model_runtime | | |---moderation | | |---tool | | |---vector_store | | └---... | ├---exception // 通用公共异常目录 | | ├---__init__.py | | ├---exception.py | | └---... | ├---extension // Flask扩展文件目录 | | ├---__init__.py | | ├---database_extension.py | | └---... | ├---handler // 路由处理器、控制器目录 | | ├---__init__.py | | ├---account_handler.py | | └---... | ├---middleware // 应用中间件目录,包含校验是否登录 | | ├---__init__.py | | └---middleware.py | | └---... | ├---migration // 数据库迁移文件目录,自动生成 | | ├---versions | | └---... | ├---model // 数据库模型文件目录 | | ├---__init__.py | | ├---account.py | | └---... | ├---router // 应用路由文件夹 | | ├---__init__.py | | ├---router.py | | └---... | ├---schedule // 调度任务、定时任务文件夹 | | ├---__init__.py | | └---... | ├---schema // 请求和响应的结构体 | | ├---__init__.py | | └---... | ├---server // 构建的应用,与app文件夹对应 | | ├---__init__.py | | └---... | ├---service // 服务层文件夹 | | ├---__init__.py | | ├---oauth_service.py | | └---... | ├---task // 任务文件夹,支持即时任务+延迟任务 | | ├---__init__.py | | └---... |---pkg // 扩展包文件夹 | ├---__init__.py | |---oauth | | ├---__init__.py | | ├---github_oauth.py | | └---... | └---... ├---storage // 本地存储文件夹 ├---test // 测试目录 ├---venv // 虚拟环境 ├---.env // 应用配置文件 ├---.env.development // 开发环境配置文件 ├---.env.production // 生产环境配置文件 ├---.env.testing // 测试环境配置文件 ├---.gitignore // 配置git忽略文件 ├---requirements.txt // 第三方包依赖管理 └---README.md // 项目说明文件

项目代码创建

.env配置

在config下创建config.py

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/5/27 21:39 @Author: sql668 @File : config.py """ import os from typing import Any from dotenv import load_dotenv from config.default_config import DEFAULT_CONFIG def _get_env(key: str) -> Any: """从环境变量中获取配置项,如果找不到择返回默认值""" return os.getenv(key, DEFAULT_CONFIG[key]) def _get_bool_env(key: str) -> bool: """从环境变量中获取布尔值配置项,如果找不到择返回默认值""" value = _get_env(key) return value.lower() == "true" if value is not None else False class Config: """配置类""" def __init__(self): # 关闭wtf的csrf保护 self.WTF_CSRF_ENABLED = _get_bool_env("WTF_CSRF_ENABLED") # print("WTF_CSRF_ENABLED", ) # 配置数据库配置 self.SQLALCHEMY_DATABASE_URI = _get_env("SQLALCHEMY_DATABASE_URI") self.SQLALCHEMY_ENGINE_OPTIONS = { 'pool_size': _get_env("SQLALCHEMY_POOL_SIZE"), 'pool_recycle': _get_env("SQLALCHEMY_POOL_RECYCLE"), } self.SQLALCHEMY_ECHO = _get_bool_env("SQLALCHEMY_ECHO") @staticmethod def load_config(): """根据环境变量加载对应配置""" env = os.getenv('APP_ENV', 'development') env_files = { 'development': '.env.development', 'testing': '.env.testing', 'staging': '.env.staging', 'production': '.env.production', } env_file = env_files.get(env, '.env') if os.path.exists(env_file): load_dotenv(env_file, override=True) else: load_dotenv('.env', override=True) class DevelopmentConfig(Config): """开发环境配置""" DEBUG = True TESTING = False class TestingConfig(Config): """测试环境配置""" DEBUG = True TESTING = True class ProductionConfig(Config): """生产环境配置""" DEBUG = False TESTING = False # 配置映射 config_by_name = { 'development': DevelopmentConfig, 'testing': TestingConfig, 'staging': DevelopmentConfig, # 预发布可以复用开发配置 'production': ProductionConfig, } def get_config(): """获取当前环境的配置类""" env = os.getenv('APP_ENV', 'development') print('env:', env) # 先加载环境变量 Config.load_config() # 返回对应的配置类 return config_by_name.get(env, DevelopmentConfig)

default_config.py

python
DEFAULT_CONFIG = { "SQLALCHEMY_DATABASE_URI": "", "SQLALCHEMY_POOL_SIZE": 30, "SQLALCHEMY_POOL_RECYCLE": 3600, "SQLALCHEMY_ECHO": "True", "WTF_CSRF_ENABLED": "False" }

控制器

在internal/handler下创建文件app_handler.py

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/5/21 23:04 @Author: sql668 @File : app_handler.py """ import os import uuid from dataclasses import dataclass from injector import inject @inject @dataclass class AppHandler: """应用控制器""" def ping(self): return {"ping": "pong"}

__init__.py

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/4/8 23:00 @Author: sql668 @File : __init__.py.py """ from .app_handler import AppHandler __all__ = [ "AppHandler" ]

路由

在internal/router下创建文件router.py

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/5/21 23:08 @Author: sql668 @File : router.py """ from dataclasses import dataclass from flask import Flask, Blueprint from injector import inject from internal.handler import AppHandler @inject # 自动注入,必须有构造函数 @dataclass # 该注解的作用是自动生成构造函数,不用手动去写 class Router: """路由""" app_handler: AppHandler def __init__(self, app_handler: AppHandler): self.app_handler = app_handler def register_router(self, app: Flask): """注册路由""" # 1. 创建一个蓝图 bp = Blueprint("llmops", __name__, url_prefix="") # 2. 将url 与对应的控制器方法做绑定 # app_handler = AppHandler() bp.add_url_rule("/ping", methods=["GET"], view_func=self.app_handler.ping) # 3. 在应用上去注册蓝图 app.register_blueprint(bp)

--init__.py

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/4/8 23:02 @Author: sql668 @File : __init__.py.py """ from .router import Router __all__ = ['Router']

Flask 应用

在internal/server下创建http.py

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/5/21 23:22 @Author: sql668 @File : http.py """ import os from flask import Flask from internal.router import Router from config import Config class Http(Flask): """Http服务引擎""" def __init__(self, *args, conf: Config,db: SQLAlchemy,router: Router, **kwargs): super().__init__(*args, **kwargs) # 初始化应用配置 self.config.from_object(conf) # 初始化数据库 db.init_app(self) # 注册应用路由 router.register_router(self)

app启动类

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/6/2 17:48 @Author: sql668 @File : module.py """ from flask_migrate import Migrate from injector import Module, Binder from internal.extension.database_extension import db from internal.extension.migrate_extension import migrate from pkg.sqlalchemy import SQLAlchemy class ExtensionModule(Module): """扩展模块的依赖注入""" def configure(self, binder: Binder) -> None: binder.bind(SQLAlchemy, to=db) binder.bind(Migrate, to=migrate)

在app/http下创建app.py

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/5/21 23:27 @Author: sql668 @File : app.py """ from injector import Injector from internal.router import Router from internal.server import Http from config import Config, get_config from app.http.module import ExtensionModule # 先加载环境变量 get_config() conf = Config() # 将 .env 加载到环境变量中 # dotenv.load_dotenv() injector = Injector([ExtensionModule]) app = Http(__name__, conf=conf,router=injector.get(Router)) if __name__ == "__main__": app.run(host="0.0.0.0", port=8080, debug=True)

运行

bash
python -m app.http.app ## requirements 安装依赖 ```bash pip install --no-deps pipreqs pip install yarg==0.1.9 docopt==0.6.2

生成requirements.txt

bash
pipreqs --ignore venv --force
## 补充 ### Flask-wtf Flask-wtf 是基于 wtforms 封装的 Flask 插件,支持 CSRF保护、快速提取数据、自定义验证规则及 wtforms的所有规则。 wtforms 支持提取的数据类型:布尔值、日期、文本、时间、浮点数、邮箱、文件、音频、整数、自定义数据类型等。 wtforms 支持校验的规则:必填、长度、邮箱、正则、范围、 UUID 、数据可选、 URL 等。 安装 ```bash pip install -U Flask-WTF

使用 在internal/schema下创建app_schema.py

python
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @Time : 2026/5/27 21:12 @Author: sql668 @File : app_schema.py """ from flask_wtf import FlaskForm from wtforms import StringField from wtforms.validators import Length, DataRequired class CompletionReq(FlaskForm): """基础聊天请求验证""" # 必填,长度最大为2000 query = StringField('query', validators=[ DataRequired(message="用户的提问是必填"), Length(max=2000, message="用户的提问最大长度是2000"), ], description="用户输入")
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:繁星

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!