I have a flask application that looks somewhat like this:
app.py
blueprints/
www.py
shop.py
app.py imports blueprint objects from each of the files in the blueprints directory and registers them with the Flask object in app.py with an appropriate subdomain (also imported from the file). Each blueprint registers error handlers, however these are only invoked when a view manually calls abort(), not by general errors (i.e. calling a non existent URL on the subdomain managed by shop.py invokes the error handler on app.py instead.)
Is there any way to force flask to pass errors to the blueprint that is handling the subdomain in which that error is occurring?
Flask's documentation says that this is not possible for 404s and 500s. If you need this functionality you might be able to use a wildcard route in your blueprint to handle 404s:
#a_blueprint.route("<path:invalid_path>")
def missing_resource(invalid_path):
return "There isn't anything at " + invalid_path, 404
You can use current_app and put it in the blueprints. Something like:
shop.py
from flask import current_app
#current_app.errorhandler(404)
def page_not_found(e):
return redirect(url_for('shop.index'))
Related
I have a site built with Flask. It has several sections, each with a dedicated blueprint. The templates in each blueprint extend a base template, which has the basic layout for each page, including a navigation bar with tabs for each section.
I'd like to have the base template highlight the current tab, so it needs to know which blueprint's view is handling the request.
One way I came up with to do this is to add a before_request handler to each blueprint and store the name in g:
bp = Blueprint('blog', __name__, url_prefix='/blog')
#bp.before_request
def set_bp_name():
g.section = 'blog'
But Flask must know which blueprint is handling a request (if any) and the blueprint, of course, knows its own name. Is there a way for the template to fetch the current blueprint's name that doesn't require modifying each blueprint?
Yes. Quite simply: request.blueprint.
The request object is one of a few (along with g) that Flask makes available to all templates. It contains the blueprint property, which is the name of the blueprint handling the current request.
For the past two days I've been trying to intergrate flask-admin to my already existing flask application. But the problem is that I keep getting the same error:
builtins.AssertionError
AssertionError: A name collision occurred between blueprints <flask.blueprints.Blueprint object at 0x000001D8F121B2B0> and <flask.blueprints.Blueprint object at 0x000001D8ECD95A90>. Both share the same name "admin". Blueprints that are created on the fly need unique names.
and that error comes from this block of lines:
Main flask application:
app.route("/admin")
def admin():
if not session.get('logged_in'):
return redirect(url_for('login'))
return adminScreen.adminPage()
admin.py
def adminPage():
admin=Admin(app)
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Role, db.session))
admin.add_view(ModelView(PointOfSale, db.session))
return admin
And what I want to do is to manage the users that I already have in my database by using the functions that flask-admin provide.
So my question is; is there a simple way to route flask-admin to my pre-existing flask application?
P.S I already know that there is this post from May of 2018, but I have no idea how to implement the solution that was provided.
You don't have to create an app.route("/admin") yourself. That is provided by the built-in blueprint from flask-admin.
In order to use blueprints correctly you should update your app to use app factory instead global variable. Otherwise you cannot have multiple instances of the application.
In existing project it may require some work to do but it's worth it.
Example factory may looki like this:
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend
app.register_blueprint(admin)
app.register_blueprint(frontend)
return app
You can find more information here:
http://flask.pocoo.org/docs/1.0/patterns/appfactories/
I'm trying to build documentation for a Flask webapp that includes a REST-like API built into it. I'm using sphinx, specifically the httpdomain extension from sphinxcontrib, using the autohttp.flask module to auto-generate my Flask docs, and the autohttp.qrefflask module to auto-generate a quick reference table to go along with it. However, when I try to build my sphinx docs (make html), I'm running into the error of conflicting route endpoints
Exception occurred:
File "/Users/../anaconda2/lib/python2.7/site-packages/flask/app.py", line 1051, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function: api.View1:add_config
I only really care about generating documentation for my API and none of the Flask web routes, so I've restricted my sphinx documentation to only build the api blueprints. Here is my sphinx api.rst
.. qrefflask:: myapp.web:create_app(debug=True)
:undoc-static:
:endpoints:
:blueprints: api
:order: path
.. autoflask:: myapp.web:create_app(debug=True)
:undoc-static:
:endpoints:
:blueprints: api
:order: path
My Flask app and Blueprint layout is as follows:
myapp/
api/
__init__.py (api blueprint defined here)
view1.py
view2.py
view3.py
web/
__init__.py (main Flask app created here via create_app)
I'm wondering if it's a problem with how I'm registering the blueprint, and that sphinx somehow is registering it twice, but I don't understand it.
My api.__init__.py basically has my Blueprint definition and a few custom error handlers:
from flask import Blueprint, jsonify
theapi = Blueprint("api", __name__, url_prefix='/myapp/api')
#theapi.errorhandler(500)
def internal_server_error(err):
messages = {'error': 'internal_server_error',
'message': err.description,
'traceback': get_traceback(asstring=True)}
return jsonify({
'api_error': messages,
}), 500
while my main Flask app creation, web.__init__.py just imports this and registers everything:
def create_app(debug=False, local=False):
from myapp.api import theapi as api
from myapp.api.view1 import View1
...
app = Flask(__name__, static_url_path='/myapp/static')
...
View1.register(api)
app.register_blueprint(api)
return app
If I move the api blueprint definition and error_handlers into the main app creation, everything works fine. But then that breaks the modularity of it. I'd like to keep my api stuff inside the api module. Also, if remove either the main autoflask or qrefflask generation, and only use one, everything works fine. But I'd really like to have the quick reference guide. The code itself runs fine, but the damn documentation is failing to build. Does anyone have any suggestions?
I want to use Flask blueprints to organize my Flask-Restful resources into separate url prefixes. Regardless of what url prefix I set (during either blueprint creation or registration), everything gets mapped to the raw route paths. How do I correctly use Restful with blueprints?
app = Flask(__name__)
api = Api(app)
api.add_resource(Building, '/<int:id>', endpoint='building')
api.add_resource(Jack, '/<int:id>', endpoint='jack')
building_api = Blueprint('building_api', __name__)
jack_api = Blueprint('jack_api', __name__)
app.register_blueprint(building_api, url_prefix='/buildings')
app.register_blueprint(jack_api, url_prefix='/jacks')
All documentation I can find says that these should now be available at /buildings/<int:id> and /jacks/<int:id>, but both of those urls 404 and instead I can access the building one at /<int:id>. Hard coding the path in add_resource fixes it, but defeats the point of url_prefix.
You need to pass the blueprint to the Api instance, not the app.
building_bp = Blueprint('buildings', __name__)
building_api = Api(building_bp)
building_api.add_resource(Building, '/<int:id>')
app.register_blueprint(building_bp, url_prefix='/buildings')
This is zhe best way to do with blueprint:
from flask import Flask, Blueprint
from flask_restful import Api, Resource, url_for
app = Flask(__name__)
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
app.register_blueprint(api_bp)
you should send Blueprint'instance to Api
I do not know why but I struggled using the Blueprint as mentioned in the answers.
But here's a quick solution I found while going through the doc link. Making use of the prefix parameter in Api() does the job.
app = Flask(__name__)
api = Api(app, prefix='/buildings')
Now, all your routes will be prefixed with /buildings. Just make sure you use url_for('link') in places where you might have simply used a /link.
One more strange thing I noticed is that atleast for me, it did not work until I renamed my routes to the same name as their class names. For example, Class Home(Resource) should have a route to /home. Using /homeepage or any other route for Home Class causes an error. Not sure if it is only me.
I am trying to setup variable route handling in a Flask application such as described in this answer: Dynamic Subdomain Handling in a Web App (Flask)
However, I want to be able to recognize certain subdomains BEFORE they are caught by the variable route so I can use the flask-restful api extension (Routing with RESTful).
For example, I have tried the following:
#app.route('/', subdomain="<user>", defaults={'path':''})
#app.route('/<path:path>', subdomain="<user>")
def user_profile(user,path):
pass
class Api(restful.Resource):
def get(self):
#Do Api things.
api.add_resource(Api, '/v1', subdomain="api")
When I test this, all of URLs go to the variable route handler and call user_prof(). I tried putting the api route first and the standard #app.route rule second and vice versa but there was no change.
Am I missing some other parameter or need to go deeper in Flask to make this happen?
Update:
The URL patterns I am trying to match are like this:
user1.mysite.com -> handled by user_profile()
user2.mysite.com -> handled by user_profile()
any_future_string.mysite.com -> handled by user_profile()
api.mysite.com/v1 -> handled by Api class
Other cases include:
www.mysite.com -> handled by index_display()
mysite.com -> handled by index_display()
#app.before_request
def before_request():
if 'api' == request.host[:-len(app.config['SERVER_NAME'])].rstrip('.'):
redirect(url_for('api'))
#app.route('/', defaults={'path': ''}, subdomain='api')
#app.route('/<path:path>', subdomain='api')
def api(path):
return "hello"
This should work. Add your api version to the path if needed or that could be processed by your API class.
To keep it simple, I redesigned the logic of my application into two distinct parts.
This way the Flask application only handles the API endpoint logic. The user profile logic is handled by another application. I can now add multiple Resources to the API application without worry about breaking the routing.