Search code examples
flaskfactory-pattern

Access @App decorator in Flask using Factory Pattern


How do you access the app object using the factory pattern for decorators? I'm aware that current_app exists, but I can't use that for decorators.

Before using the factory pattern (eg. wrapping App initialization and blueprint registration in a function) I could just do something like:

@app.errorhandler(500)
@app.errorhandler(502)
def generic_errror_handler(error):
    # Some logic here
    return render_template('error.html', error=errror)

But after using the factory pattern I don't see how to achieve this in a good way. Do you initialize them inside the create_app() function?

def create_app():
    app = Flask(__name__)
    initialize_extensions(app)
    register_blueprints(app)
    return app

Solution

  • You can initialize the handlers within the create_app definition, e.g.

    def create_app():
        app = Flask(__name__)
        initialize_extensions(app)
        register_blueprints(app)
    
        @app.errorhandler(500)
        @app.errorhandler(502)
        def generic_errror_handler(error):
            # Some logic here
            return render_template('error.html', error=errror)
    
        return app
    

    Or, create a separate Python file, say error_handlers.py (example taken from Quokka CMS):

    def register_handlers(app):
        if app.config.get('DEBUG') is True:
            app.logger.debug('Skipping error handlers in Debug mode')
            return
    
        @app.errorhandler(403)
        def forbidden_page(*args, **kwargs):
            # do stuff
            return render_template("errors/access_forbidden.html"), 403
    
        @app.errorhandler(404)
        def page_not_found(*args, **kwargs):
            # do stuff
            return render_template("errors/page_not_found.html"), 404
    
        @app.errorhandler(405)
        def method_not_allowed_page(*args, **kwargs):
            # do stuff
            return render_template("errors/method_not_allowed.html"), 405
    
        @app.errorhandler(500)
        def server_error_page(*args, **kwargs):
            # do stuff
            return render_template("errors/server_error.html"), 500
    

    and call register_handlers from within create_app:

    def create_app():
        app = Flask(__name__)
        initialize_extensions(app)
        register_blueprints(app)
    
        register_handlers(app)
    
        return app