20

I have a flask api which I have wrapped up in an object. Doing this has made unit testing a breeze, because I can instantiate the api with a variety of different settings depending on whether it is in production, test, or whatehaveyou.

I am now trying to extend the api a bit, and for that I'm using a blueprint. The problem is that I cannot figure out how to pass arguments to the blueprint. My routes require information like which database to access, and that information is not static. How can I pass this information into a blueprint? I have included code below as an example:

api.py:

class MyApi(object):
    def __init__(self, databaseURI):
     self.app = Flask(__name__)
     self.app.register_blueprint(myblueprint)

blueprint.py

myblueprint= Blueprint('myblueprint', __name__)
@myblueprint.route('/route', methods=['GET'])
def route():
  database = OpenDatabaseConnection(databaseURI)

There is a related question here: How do I pass constructor arguments to a Flask Blueprint?

But the people who answer the question solve the op's use-case specific problem without actually answering the question of how to pass arbitrary arguments to a blueprint.

Community
  • 1
  • 1
melchoir55
  • 6,842
  • 7
  • 60
  • 106

4 Answers4

40

You could create the blueprint dynamically in a constructor function:

def construct_blueprint(database):

    myblueprint = Blueprint('myblueprint', __name__)

    @myblueprint.route('/route', methods=['GET'])
    def route():
        database = database

    return(myblueprint)
syntonym
  • 7,134
  • 2
  • 32
  • 45
  • 2
    Great idea! And I certainly appreciate it. The problem here is that part of the reason I wanted to use a blueprint was for the sake of organization. I don't really want a multi-thousand line long python file. I want to split the blueprints into respective files. To my knowledge, it isn't possible to spread a class definition across multiple files in python. I realize I could create a chain of "extension" classes, but that seems a bit hackish. – melchoir55 Feb 21 '15 at 01:50
  • 7
    What is stopping you from putting that function in a module and then using it `myblueprint = module.construct_blueprint(database)`? – syntonym Feb 21 '15 at 01:52
  • 11
    Only my end-of-the-day tiredness. Thank you sir. – melchoir55 Feb 21 '15 at 01:56
6

Use Flask config system (app.config) to store all your config data, then from your Blueprint read your Application Context using current_app.

Store in app.config:

app.config[DATABASE_URI] = databaseURI

Read application context:

databaseURI = current_app.config[DATABASE_URI]

Sample code

main.py

from flask import Flask
from blueprint import myblueprint

app = Flask(__name__)
app.register_blueprint(myblueprint)
app.config[DATABASE_URI] = databaseURI

blueprint.py

from flask import current_app

myblueprint= Blueprint('myblueprint', __name__)
@myblueprint.route('/route', methods=['GET'])
def route():
  databaseURI = current_app.config[DATABASE_URI]
  database = OpenDatabaseConnection(databaseURI)
ssoler
  • 4,884
  • 4
  • 32
  • 33
0

This way it's possible to add a blueprint, passing parameters, inside an appfactory. Sometimes you'll need it and it's not described anywhere in the flask docs.

Assuming bp1.py, bp2.py are in the same folder as your appname

from appname import bp1, bp2

app.register_blueprint(bp1.bp)
# with parameters:
app.register_blueprint(bp2.construct_blueprint(arg1, arg2))

inside bp2.py:

def construct_blueprint(arg1, arg2):
    bp = Blueprint("bp2", __name__)

    @bp.route('/test')
    def test():
        ret = {'arg1': arg1, 'arg2': arg2}
        return jsonify(ret)

    return bp
dignitas123
  • 71
  • 1
  • 6
0

I went about this in a slightly different way by creating a class in the helper blueprints python files. This way I can have one call to load the class and then pass the result to the blueprint function in the main python script. When I load the class I can pass any attributes I've configured. I like this approach as it keeps my code much cleaner.

The code I've put in here can also be found at https://github.com/dacoburn/example-flask-blueprints if you want to download it. I added comments to the github with more details of what is going on in the python files.

The folder structure I have is: src |___main.py |___routes |___index.py |___example.py |___templates |___index.html |___example.html

main.py

from flask import Flask
import os
from routes.index import Index
from routes.example import Example

app = Flask(__name__)
index = Index("Example User")
example = Example("Random Arg")
app.register_blueprint(index.index)
app.register_blueprint(example.example)

if __name__ == '__main__':
    port = int(os.environ.get('APP_PORT', 5000))
    app.run(host='0.0.0.0', port=port, debug=True)

index.py

from flask import render_template, Blueprint


class Index:

    def __init__(self, username):
        self.username = username
        self.index = self.create_index()

    def create_index(self):
        index_page = Blueprint("index", __name__)

        @index_page.route("/", methods=['GET'])
        def index():
            return render_template("index.html", username=self.username)

        return index_page

example.py

from flask import render_template, Blueprint


class Example:

    def __init__(self, arg):
        self.arg = arg
        self.example = self.create_example()

    def create_example(self):
        example_page = Blueprint("example", __name__)

        @example_page.route("/<username>", methods=['GET'])
        def example(username):
            return render_template("example.html",
                                   username=username,
                                   arg=self.arg)

        return example_page

index.html

<html>
    <head>
        <title>Example Page</title>
    </head>
    <body>
    <p>Hello {{ username }}</p>
    <br>
    This page also has a redirect to another route:
    <ul>
        <li><a href="/{{ username }}">Example Page</a></li>
    </ul>
    </body>
</html>

example.html

<html>
    <head>
        <title>Example Page 2</title>
    </head>
    <body>
    <p>Hello {{ username }}</p>
    <br>
    Here is the random argument: {{ arg }}
    <br>
    <br>
    This page also has a link to the main page:
    <ul>
        <li><a href="{{ url_for('index.index') }}">Index Page</a></li>
    </ul>
    </body>
</html>
Douglas C.
  • 56
  • 5