在大型应用程序中使用 Flask Restful 作为蓝图

Using Flask Restful as a Blueprint in Large Application

我正在尝试使用 Flask restful 作为适用于其他蓝图的模式中的蓝图。我不断收到以下错误消息

我收到以下错误消息

AttributeError: 'Blueprint' object has no attribute 'add_resource'

我的项目设置如下:

文件夹结构

├── app
│   ├── __init__.py
│   ├── api
│   │   ├── __init__.py
│   │   └── routes.py
│   ├── main
│   │   ├── __init__.py
│   │   ├── forms.py
│   │   └── views.py
│   └── templates
│       ├── base.html
│       └── home.html
├── config.py
├── manage.py
└── requirements.txt

__init__.py

from flask import Flask
from flask_restful import Api
from flask_bootstrap import Bootstrap
from config import config
bootstrap = Bootstrap()
api = Api()

def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    bootstrap.init_app(app)
    api.init_app(app)

    from .main import main as main_blueprint
    from .api import api as api_blueprint
    app.register_blueprint(main_blueprint)
    app.register_blueprint(api_blueprint)
    return app

api/__init__.py

from flask import Blueprint

api = Blueprint('api', __name__)

from . import routes

api/routes.py

from flask_restful import Resource
from . import api

class TodoItem(Resource):
    def get(self, id):
        return {'task': 'Say "Hello, World!"'}

api.add_resource(TodoItem, '/todos/<int:id>')

我做错了什么??

由于您如何命名蓝图 api,同时还使用 flask_restful 中的 api 对象,您 运行 遇到了麻烦。在您的 routes.py 中,您明确地从 api/__init__.py 导入 api,这是一个 Blueprint 对象。您不能将 add_resource 调用到 Blueprint 对象,只能调用 flask_restful 中的 Api 对象。

如果您将导入更改为:

from .. import api

您将导入正确的对象。无论如何,我仍然建议更改您的蓝图名称以避免此类混淆。

如果您按照 https://flask-restful.readthedocs.io/en/0.3.5/intermediate-usage.html

中的说明进行操作

这里的关键点是创建一个 Flask Blueprint 实例并将其传递给 flask-restfuls 的 Api class.

的新实例

最后,确保在 create_app 函数中注册 flask-restful api 蓝图:app.register_blueprint(api_bp)

from flask import Flask, Blueprint
from flask_restful import Api
from flask_bootstrap import Bootstrap
from config import config

bootstrap = Bootstrap()
api_bp = Blueprint('api', __name__)
api = Api(api_bp)

def create_app(config_name):
   app = Flask(__name__)
   app.config.from_object(config[config_name])
   config[config_name].init_app(app)

   bootstrap.init_app(app)

   from .users import main as users_blueprint
   from .blogs import main as blogs_blueprint

   # blueprints for blogs & users
   app.register_blueprint(users_blueprint)
   app.register_blueprint(blogs_blueprint)
   app.register_blueprint(api_bp)
   
   return app

另请注意,您不再需要注册 api.init_app(app)

如果你想要基于资源的子模块(比如你的 /api)...

例如:文件夹结构

├── app
│   ├── __init__.py
│   ├── foo
│   │   ├── __init__.py
│   │   └── routes.py
│   ├── boo
│   │   ├── __init__.py
│   │   └── routes.py
├── config.py
├── manage.py

... 并使用 url_prefix 注册他们的蓝图,以便在每个添加的资源中不重复公共部分。在每个模块中创建新的 Api 实例并传递给它一个蓝图。

foo/__init__.py

from flask import Blueprint                            
from flask_restful import Api
                                                       
foo_bp = Blueprint('foo', __name__, url_prefix='/foo') 
foo_api = Api(foo_bp)  
                                                                                     
from . import routes 

在路由中导入 foo_api 并向其添加资源

foo/routes.py

from flask_restful import Resource
from . import foo_api

class TodoItem(Resource):
    def get(self, id):
        return {'task': 'Say "Hello, World!"'}

foo_api.add_resource(TodoItem, '/todos/<int:id>')
                          

然后在主应用程序中 __init__.py 只需导入模块蓝图并注册它。您甚至不需要添加“主”应用程序蓝图。如果您要从主应用程序 __init__ 导入 api,那么您无法使用它自己的参数注册每个蓝图,例如 url_prefix.

__init__.py

from flask import Flask
from config import config

def create_app(config_name):
   app = Flask(__name__)
   app.config.from_object(config[config_name])
   config[config_name].init_app(app)

   from .foo import foo_bp
   from .boo import boo_bp

   app.register_blueprint(foo_bp)
   app.register_blueprint(boo_bp)

   return app

您可以在注册蓝图(优先)或创建蓝图时设置url_prefix。要检查路线,您可以打印 app.url_map