V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
LeeReamond
V2EX  ›  问与答

FastAPI 的正确工程化方式是什么样的?

  •  
  •   LeeReamond · 2021-02-09 17:57:45 +08:00 · 1193 次点击
    这是一个创建于 1417 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,重构项目时组织文件遇到一个循环导入问题。

    通常 web 应用做法是将视图单独拿出来放在一起,路由也拿出来放在一起,等等等等,然后启动服务时从程序入口一股脑的导入。但是为了方便使用,我们希望将程序所有配置集中起来放在入口处,这样启动时就可以轻易地开关功能。

    所以比如一个典型情况,在程序入口(假设名为 app.py )处我们需要定义一个 jinja2 template,这种模板文件夹的位置属于配置问题,不适合写死在业务模块里。但这些 template 又需要被业务模块所调用,比如某个路由返回某个渲染后的模板之类的。这就产生了,视图需要导入 app.py 里的内容,而 app.py 又需要导入视图才能运行,产生了循环导入的问题。

    通常的 web 框架有很多变通的解决办法,比如偏函数、装饰器、或者一些共享状态组件之类的。但是 fastapi 由于注入了参数化模块,导致比如在下面的视图逻辑中

    @app.get('/')
    async def root(request:Request , template: jinja2.Tmeplate):
        return template.RenderResponse('index.html' , {'title':'hello world'})
    
    root = functools.partial(template = template)
    

    比如这种方式是行不通的,所有输入参数都会被 fastapi 拿来进行参数检查。

    7 条回复    2021-02-11 07:26:43 +08:00
    johnsona
        1
    johnsona  
       2021-02-09 20:54:48 +08:00 via iPhone
    fullstack-fastapi 这个仓库
    LeeReamond
        2
    LeeReamond  
    OP
       2021-02-10 11:05:47 +08:00
    @johnsona 看了一下,还是没有解决工程问题,他这个 app=FastAPI()和视图是写在一起的。

    另外看有几个人收藏这个帖子了,本着负责的态度回复一下我目前的解决方案。我由于前段时间研究了一下 PEP563,所以自然地想到运行时获取 globals 的方法,无论导入过程如何,运行时都可以比较简单地从 sys.modules 里获得实例对象。理论上这个做法不会产生安全问题、不会被 deprecated,算是一定程度上的 hack,寻址速度方面基本也可以忽略影响,目前是堪用。

    但是最好还是不 hack,所以我来 v2 问一下大家的做法,但是似乎没人回复
    johnsona
        3
    johnsona  
       2021-02-10 13:02:35 +08:00 via iPhone
    @LeeReamond 听起来有点像 flask 循环引用的问题 办法有 在 app.py 结尾引入视图。2,通过传入 app 而不是 import app 方式把 app 给视图 3 类似 flask 蓝图的东西
    LeeReamond
        4
    LeeReamond  
    OP
       2021-02-10 17:03:47 +08:00 via Android
    @johnsona 问题在于无法传入,视图最终逻辑函数的参数是固定的,你不能引入一些与 http 无关的其他业务参数
    johnsona
        5
    johnsona  
       2021-02-10 17:15:15 +08:00 via iPhone
    @LeeReamond
    def register ( app ):
    @app.route
    def hello ():
    return 1
    不知道是否要这个
    LeeReamond
        6
    LeeReamond  
    OP
       2021-02-11 04:40:18 +08:00 via Android
    @johnsona 你怎么把 register 和 hello()联系起来。比如我在 main.py 中有这几行代码

    app=fastapi()
    template=jinja2.template()

    然后视图中有
    @app.get()
    def hello()
    return template.render('index.html')
    johnsona
        7
    johnsona  
       2021-02-11 07:26:43 +08:00 via iPhone
    @LeeReamond from xxx import register
    register ( app )
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2839 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 08:50 · PVG 16:50 · LAX 00:50 · JFK 03:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.