python flask紅圖(Redprint)實現以及自動註冊到藍圖

Excel2016發表於2024-06-20

透過掃包的方式獲取app.api.v1(這個是你的紅圖所在的包)下的所有module
透過判斷這個module下有api的屬性並且是Redprint

if hasattr(module, "api") and isinstance(module.api,Redprint):

滿足這兩個條件就可以呼叫module.api.register(bp_v1)方法把對應的紅圖註冊了
app.api.v1.__init__.py

import importlib
import pkgutil

from flask import Blueprint
from app.libs.redprint import Redprint


def create_blueprint_v1():
    bp_v1 = Blueprint('v1', __name__)

    modules = find_modules("app.api.v1")
    for module in modules:
        if hasattr(module, "api") and isinstance(module.api,Redprint):
            module.api.register(bp_v1)
    return bp_v1


def find_modules(package_name):
    # 匯入指定的包
    package = importlib.import_module(package_name)

    # 獲取包的路徑
    package_path = package.__path__

    modules = []

    # 遍歷包下的所有模組
    for module_info in pkgutil.iter_modules(package_path):
        # 獲取模組的完整名稱
        module_full_name = f"{package_name}.{module_info.name}"
        try:
            # 匯入模組
            module = importlib.import_module(module_full_name)
            modules.append(module)
        except ImportError as e:
            print(f"Failed to import {module_full_name}: {e}")

    return modules

redprint.py



class Redprint:
    def __init__(self, name):
        self.name = name
        self.mound = []

    def route(self, rule, **options):
        def decorator(f):
            self.mound.append((f, rule, options))
            return f
        return decorator

    def register(self, bp, url_prefix=None):
        if url_prefix is None:
            url_prefix = '/' + self.name
        for f, rule, options in self.mound:
            endpoint = f'{self.name}+{options.pop("endpoint", f.__name__)}'
            bp.add_url_rule(url_prefix + rule, endpoint, f, **options)

藍圖註冊到app

def register_blueprints(app):
    from app.api.v1 import create_blueprint_v1
    app.register_blueprint(create_blueprint_v1(), url_prefix='/v1')

def create_app():
    app = Flask(__name__)
    ...
    register_blueprints(app)
    ...

使用
app.api.v1.user.py

api = Redprint('user')

@api.route('/<int:uid>', methods=['GET'])
@auth.login_required
def super_get_user(uid):
    ...

@api.route('', methods=['GET'])
@auth.login_required
def get_user():
    ...

相關文章