Reputation: 2061
I am trying to use Flask restful as a Blueprint in a pattern that works for other blueprints. I keep getting the following error message
I get the following error message
AttributeError: 'Blueprint' object has no attribute 'add_resource'
My project setup is as follows:
Folder structure
├── 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>')
What am I doing wrong??
Upvotes: 5
Views: 17858
Reputation: 1485
If you follow the instructions from https://flask-restful.readthedocs.io/en/0.3.5/intermediate-usage.html
The key points here are to create a Flask Blueprint instance & pass it to a new instance of flask-restfuls's Api class.
Lastly, make sure to register the flask-restful api blueprint within your create_app function: 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
Also note, you don't need to register api.init_app(app)
anymore.
Upvotes: 7
Reputation: 581
If you want to have submodules (like your /api) based on resources...
Eg: folder structure
├── app
│ ├── __init__.py
│ ├── foo
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── boo
│ │ ├── __init__.py
│ │ └── routes.py
├── config.py
├── manage.py
... and register their blueprints with url_prefix to not repeat the common part in each added resource. Create new Api instance in each module and pass to it a blueprint.
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
in routes import foo_api and add resources to it
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>')
Then in main application __init__.py just import modules blueprints and register it. You dont even need to add a "main" application blueprint. If you would import the api from main application __init__ then you can't register each blueprint with it's own params like 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
You can set the url_prefix on register blueprint (it has priority) or when you create it. To check routes you can print the app.url_map
Upvotes: 4
Reputation: 18531
You're running in to trouble because of how you've named your blueprint api
, whilst also using the api
object from flask_restful
. In your routes.py
you're explicitly importing api
from api/__init__.py
, and this is a Blueprint
object. You can't call add_resource
to a Blueprint
object, only to an Api
object from flask_restful
.
If you change your import to:
from .. import api
you'll be importing the correct object. I'd still recommend changing your blueprint name anyway to avoid this sort of confusion.
Upvotes: 2