如题,重构项目时组织文件遇到一个循环导入问题。
通常 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 拿来进行参数检查。
1
johnsona 2021-02-09 20:54:48 +08:00 via iPhone
fullstack-fastapi 这个仓库
|
2
LeeReamond OP @johnsona 看了一下,还是没有解决工程问题,他这个 app=FastAPI()和视图是写在一起的。
另外看有几个人收藏这个帖子了,本着负责的态度回复一下我目前的解决方案。我由于前段时间研究了一下 PEP563,所以自然地想到运行时获取 globals 的方法,无论导入过程如何,运行时都可以比较简单地从 sys.modules 里获得实例对象。理论上这个做法不会产生安全问题、不会被 deprecated,算是一定程度上的 hack,寻址速度方面基本也可以忽略影响,目前是堪用。 但是最好还是不 hack,所以我来 v2 问一下大家的做法,但是似乎没人回复 |
3
johnsona 2021-02-10 13:02:35 +08:00 via iPhone
@LeeReamond 听起来有点像 flask 循环引用的问题 办法有 在 app.py 结尾引入视图。2,通过传入 app 而不是 import app 方式把 app 给视图 3 类似 flask 蓝图的东西
|
4
LeeReamond OP @johnsona 问题在于无法传入,视图最终逻辑函数的参数是固定的,你不能引入一些与 http 无关的其他业务参数
|
5
johnsona 2021-02-10 17:15:15 +08:00 via iPhone
|
6
LeeReamond OP |
7
johnsona 2021-02-11 07:26:43 +08:00 via iPhone
@LeeReamond from xxx import register
register ( app ) |