如何使用Factory模式和init_app()获取范围内的组件

2024-04-26 09:42:42 发布

您现在位置:Python中文网/ 问答频道 /正文

使用Factory pattern构建一个Flask App。 大多数Flask库使用init_app()方法与工厂模式兼容

这里以Flask-RESTfull为例,但它适用于支持工厂模式的大多数其他库

文件夹结构和代码如下所示

flaskr/
├── __init__.py
└── resources
    ├── __init__.py
    └── sample_resource.py
# flaskr/__init__.py

from flask import Flask
from flask_restful import Api

api = Api()


def create_app():
    app = Flask(__name__)

    from flaskr.resources import sample_resource  # Resources need to be imported before calling init_app()
    api.init_app(app)

    return app
# flaskr/resources/sample_resource.py

from flask_restful import Resource
from flaskr import api

class UserResource(Resource):

    def get(self):
        return 'Sample Resource'

api.add_resource(UserResource, "/sample")

运行

$ export FLASK_APP=flaskr
$ flask run

问题

我面临的问题是Resources需要在范围内换句话说api.add_resource(UserResource, "/sample") 需要在^{之前调用。这将导致导入api.init_app(app)之前的所有资源

解决方案1

为了保持create_app()干净,我在flaskr/resources/__init__.py中添加了所有导入语句,并像这样导入resources

# flaskr/resources/__init__.py

from flaskr.resources import sample_resource
# flaskr/__init__.py

def create_app():
    app = Flask(__name__)

    from flaskr import resources
    api.init_app(app)

这可以保持create_app()的干净,但每次创建新资源时,我都需要在resources/__init__.py中添加导入

解决方案2

How to load all modules in a folder 这样__init__.py文件将导入包中的所有资源。即使被接受的答案不起作用(我没有探究原因) this answer成功了。因此,将文件更改为

# flaskr/resources/__init__.py

from importlib import import_module
from pathlib import Path

for f in Path(__file__).parent.glob("*.py"):
    module_name = f.stem
    if (not module_name.startswith("_")) and (module_name not in globals()):
        import_module(f".{module_name}", __package__)
    del f, module_name
del import_module, Path

这解决了整个问题,通过将上述代码添加到所有此类包(模型、模式)等,但对我来说,只需要选择文件名 以.py结尾并导入所有这些内容并不优雅。出于某种原因,如果包中有非资源文件(即使是错误的) 它可能会导致问题(请记住,这不仅适用于Flask RESTfull,还适用于使用init_app()的所有库)


问题

  1. 有没有更好的方法来构建我的应用程序,以避免在创建和删除资源的两个地方进行更改
  2. 我可以用更优雅的方法导入包中的资源吗?如果是这样的话,在避免问题时应该记住哪些要点
  3. 我是否正确理解在init_app()期间资源/模型需要在范围内

PS:另一个库作为is-SQLAlchemy(或Flask-SQLAlchemy)应用,其中模型需要在范围内 在调用^{}之前

因此-Flask app doesn't recognize flask_restful resources的答案不解决问题,因为它打破了工厂模式