目錄
- 1. 項目概述
- 2. 項目結構
- 3. 核心組件解析
- 3.1 動態模塊注冊系統 (`api/__init__.py`)
- 3.2 應用程序入口 (`setup_demo.py`)
- 4. 模塊開發指南
- 4.1 標準模塊 (`*_app.py`)
- 4.2 SDK模塊 (`sdk/*.py`)
- 5. URL路徑規則
- 6. 如何使用
- 6.1 啟動應用
- 6.2 添加新模塊
- 7. 工作原理
1. 項目概述
這個項目是一個基于Flask的動態模塊注冊系統,它允許你以一種模塊化的方式組織API端點,并且能夠自動發現和注冊這些模塊。這種架構特別適合構建可擴展的Web API服務,讓你可以輕松地添加新功能而無需修改核心代碼。
2. 項目結構
flask_path_test/
├── .venv/ # Python虛擬環境目錄
├── api/ # API模塊目錄
│ ├── __init__.py # 核心功能:動態模塊注冊系統
│ ├── product_app.py # 產品模塊
│ ├── user_app.py # 用戶模塊
│ └── sdk/ # SDK模塊目錄
│ └── auth.py # 認證SDK模塊
├── .gitignore # Git忽略文件配置
├── .python-version # Python版本配置文件
├── pyproject.toml # 項目配置文件
├── README.md # 項目說明文檔
├── setup_demo.py # 應用程序入口文件
└── uv.lock # 依賴鎖定文件
環境準備
uv init
uv venv
source .venv/bin/activate
uv pip install flask
3. 核心組件解析
3.1 動態模塊注冊系統 (api/__init__.py
)
這個文件是整個系統的核心,它實現了以下功能:
- 自動發現模塊:搜索所有符合命名規則的模塊文件
- 動態加載模塊:使用Python的importlib機制動態加載模塊
- 注冊Flask藍圖:將每個模塊注冊為Flask藍圖,并設置合適的URL前綴
- 提供主頁視圖:顯示所有已注冊的模塊及其URL
關鍵函數:
search_pages_path()
:搜索所有以_app.py
結尾的文件和SDK目錄下的Python文件register_page()
:將找到的模塊文件注冊為Flask藍圖auto_register_pages()
:自動注冊所有找到的模塊
代碼:
import sys
from pathlib import Path
from importlib.util import spec_from_file_location, module_from_spec
from flask import Flask, Blueprint# 創建Flask應用
app = Flask(__name__)
API_VERSION = "v1"
registered_urls = []def search_pages_path(pages_dir):"""搜索頁面路徑"""app_path_list = [path for path in pages_dir.glob("*_app.py") if not path.name.startswith(".")]# 搜索根目錄下的sdkapi_sdk_path_list = [path for path in pages_dir.glob("*sdk/*.py") if not path.name.startswith(".")]app_path_list.extend(api_sdk_path_list)return app_path_listdef register_page(page_path):"""注冊頁面模塊為Flask藍圖"""path = f"{page_path}"# 獲取頁面名稱(去掉_app后綴)page_name = page_path.stem.rstrip("_app")# 構建模塊名稱module_name = ".".join(page_path.parts[page_path.parts.index("api"): -1] + (page_name,))print(f"module_name: {module_name}")# 動態加載模塊spec = spec_from_file_location(module_name, page_path)page = module_from_spec(spec)# 先設置app和manager,再執行模塊代碼page.app = apppage.manager = Blueprint(page_name, module_name)sys.modules[module_name] = pagespec.loader.exec_module(page)# 獲取頁面名稱(可能在模塊中重新定義)page_name = getattr(page, "page_name", page_name)# 確定URL前綴sdk_path = "\\sdk\\" if sys.platform.startswith("win") else "/sdk/"url_prefix = (f"/api/{API_VERSION}" if sdk_path in path else f"/{API_VERSION}/{page_name}")print(f"url_prefix: {url_prefix}")# 注冊藍圖app.register_blueprint(page.manager, url_prefix=url_prefix)return url_prefixdef auto_register_pages():"""自動注冊所有頁面模塊"""global registered_urls# 創建api目錄結構api_dir = Path("api")api_dir.mkdir(exist_ok=True)# 搜索并注冊所有頁面page_paths = search_pages_path(api_dir)result = []print(page_paths)for page_path in page_paths:try:url_prefix = register_page(page_path)result.append((page_path.name, url_prefix))print(f"已注冊模塊: {page_path.name} -> {url_prefix}")except Exception as e:print(f"注冊模塊 {page_path.name} 失敗: {e}")return result@app.route('/')
def index():"""主頁顯示所有注冊的模塊"""global registered_urlshtml = "<h1>Flask 動態模塊注冊演示</h1>"html += "<h2>已注冊的模塊:</h2><ul>"for module_name, url_prefix in registered_urls:html += f"<li><strong>{module_name}</strong>: <a href='{url_prefix}'>{url_prefix}</a></li>"html += "</ul>"html += "<p>訪問上面的鏈接查看各個模塊的功能</p>"return html
3.2 應用程序入口 (setup_demo.py
)
這個文件是應用程序的入口點,它:
- 導入核心組件
- 調用
auto_register_pages()
注冊所有模塊 - 啟動Flask應用服務器
from api import app, auto_register_pages, registered_urls# 如果需要,可以在這里進行額外的配置
# app.config['SOME_CONFIG'] = 'some_value'# 運行應用程序
if __name__ == '__main__':# 清空已注冊的URL列表registered_urls.clear()# 手動注冊所有模塊result = auto_register_pages()registered_urls.extend(result)print(f"已注冊的URL: {registered_urls}")# 運行應用程序app.run(debug=True, port=5000)
4. 模塊開發指南
4.1 標準模塊 (*_app.py
)
標準模塊文件需要遵循以下規則:
- 文件名必須以
_app.py
結尾(例如:user_app.py
、product_app.py
) - 模塊中可以定義
page_name
變量來自定義URL路徑(可選) - 使用
@manager.route()
裝飾器定義路由
示例(product_app.py
):
from flask import jsonify# 可以自定義頁面名稱
page_name = "products"@manager.route('/')
def product_list():"""產品列表接口"""return jsonify({"message": "產品模塊","products": [{"id": 1, "name": "筆記本電腦", "price": 5999},{"id": 2, "name": "智能手機", "price": 2999}]})@manager.route('/<int:product_id>')
def product_detail(product_id):"""產品詳情接口"""return jsonify({"message": f"產品詳情 - ID: {product_id}","product": {"id": product_id, "name": f"產品{product_id}", "price": 1000 + product_id * 100}})
示例(user_app.py
):
from flask import jsonify@manager.route('/')
def user_list():"""用戶列表接口"""return jsonify({"message": "用戶模塊","users": [{"id": 1, "name": "張三", "email": "zhangsan@example.com"},{"id": 2, "name": "李四", "email": "lisi@example.com"}]})@manager.route('/<int:user_id>')
def user_detail(user_id):"""用戶詳情接口"""return jsonify({"message": f"用戶詳情 - ID: {user_id}","user": {"id": user_id, "name": f"用戶{user_id}", "email": f"user{user_id}@example.com"}})
4.2 SDK模塊 (sdk/*.py
)
SDK模塊放置在api/sdk/
目錄下,它們會被自動注冊到/api/v1
路徑下。
示例(sdk/auth.py
):
from flask import jsonify, request@manager.route('/', methods=['GET'])
def login():"""登錄接口"""return jsonify({"message": "SDK認證模塊 - 登錄","token": "fake_jwt_token_12345","expires_in": 3600})
5. URL路徑規則
系統會根據模塊類型和名稱自動生成URL路徑:
- 標準模塊:
/v1/{page_name}/
- 例如:
/v1/products/
、/v1/user/
- 例如:
- SDK模塊:
/api/v1/
- 例如:
/api/v1/
(auth模塊)
- 例如:
6. 如何使用
6.1 啟動應用
uv run setup_demo.py
應用將在http://localhost:5000
啟動,訪問主頁可以看到所有已注冊的模塊列表。
6.2 添加新模塊
- 在
api/
目錄下創建新的*_app.py
文件 - 定義路由函數
- 重啟應用,新模塊會被自動發現和注冊
示例(創建新的order_app.py
):
from flask import jsonify# 可以自定義頁面名稱
page_name = "orders"@manager.route('/')
def order_list():"""訂單列表接口"""return jsonify({"message": "訂單模塊","orders": [{"id": 1, "product_id": 1, "user_id": 1, "status": "已付款"},{"id": 2, "product_id": 2, "user_id": 2, "status": "待發貨"}]})
7. 工作原理
setup_demo.py
啟動時調用auto_register_pages()
auto_register_pages()
搜索所有符合規則的模塊文件- 對每個找到的文件,調用
register_page()
進行注冊 register_page()
動態加載模塊,并將其注冊為Flask藍圖- 所有注冊的URL保存在
registered_urls
列表中,并在主頁中顯示
這個Flask動態模塊注冊系統提供了一種優雅的方式來組織和擴展你的API服務。通過遵循簡單的命名約定和目錄結構,你可以輕松添加新功能而無需修改核心代碼。這種模塊化的設計特別適合大型項目,讓團隊成員可以獨立開發不同的功能模塊。