玩转FastAPI之动态路由注册(五)

1,069 阅读2分钟

原来的官方方式要自己import,然后注册到路由列表里面。感觉麻烦,有没有我自己写好controller层,自己注册路由呢。后面研究下,发现可以。

1.在system.py里面写类似这个代码

def initRouter(app: FastAPI):
    for root, dirs, files in os.walk(os.path.join(os.getcwd(), "router")):  
        for file in files:  
            if file.find("__init__") > -1 or file.find(".pyc") > -1:  
                continue  
            file = file.replace(".py", "")  
            m = importlib.import_module('router.'+file)  
            app.include_router(m.router)
class Init:  
    @staticmethod  
    def do(app: FastAPI):  
        initRouter(app)   

原理就是获取在router文件夹下面的文件然后导入模块自己注册到路由

如果有需要打包为exe文件用

def initRouter(app: FastAPI):
        # 解析规则:放在router模块下面的文件 (文件夹下文件)
        # 是否为已打包环境
        if getattr(sys, "frozen", False):
            base_path = os.path.join(sys._MEIPASS, "router")
        else:
            base_path = os.path.join(os.getcwd(), "router")

        # 获取当前目录下所有非目录项(即文件)
        files_in_current_dir = [
            f
            for f in os.listdir(base_path)
            if os.path.isfile(os.path.join(base_path, f))
        ]

        for file in files_in_current_dir:
            file = file.replace(".py", "")
            if file in ["__init__", ".pyc"]:
                continue
            module = importlib.import_module("router." + file)
            if hasattr(module, "router"):
                app.include_router(module.router)

2.调用初始化路由

from util.system import Init
app = FastAPI()  
  
Init.do(app)  
  
  
if __name__ == '__main__':  
    uvicorn.run('main:app', host='0.0.0.0', port=8000, reload=True, workers=1)

上面第一步是简单版本得。局限是不能多层级嵌套,只能放在某个文件夹下顶级的文件。适合做点简单的测试原型,或微小项目

image.png 优化版本如下,支持在不同文件夹下。一个文件夹是一个模块。比较适合业务比较多的时候

image.png

def initRouter(app: FastAPI):
        # 解析规则:server模块下面的带controller字符的文件 (文件夹下特定文件)
        for path in Path(os.getcwd() + "/server").rglob("*.py"): 
            # 使用pathlib更方便地遍历文件
            if "controller" in path.name.lower():
                module_name = path.stem  # 不包含扩展名的文件名
                try:
                    # 动态导入模块
                    full_module_name = f"server.{path.parent.name}.{module_name}"
                    module = importlib.import_module(full_module_name)
                    # 添加路由
                    if hasattr(module, "router"):
                        app.include_router(module.router)
                except Exception as e:
                    print(f"导入模块失败: {full_module_name} : {e}")

简单版本 github.com/MrYZhou/cod… 优化版本 github.com/MrYZhou/lga…

总结:动态注册配合热更新,我再也不用手动关心怎么注册到应用。最后我觉得python框架这块应该自己写个装饰器给我们用才对。就像boot那样@Controller自动注入。这点肯定可以实现的。最后希望大家能喜欢我的分享。