111

I'm having trouble understanding how to split a flask app into multiple files.

I'm creating a web service and I want to split the api's into different files (AccountAPI.py, UploadAPI.py, ...), just so I don't have one huge python file.

I've read that you can do this with Blueprints, but I'm not entirely sure that route is the right one for me.

Ultimately I want to run one Main python file and include other files so that when it runs, they are considered one big file.

For example if I have Main.py and AccountAPI.py I want to be able to do this:

Main.py:

from flask import Flask
import AccountAPI

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

AccountAPI.py:

@app.route("/account")
def accountList():
    return "list of accounts"

I know with this example it obviously won't work, but is it possible to do something like that?

Thanks

user1751547
  • 2,211
  • 4
  • 21
  • 25
  • 1
    I found that many StackOverflow pages and other sites have solutions demanding the use of a blueprint. It's not necessary. A regular Python module will do. – plutownium Sep 06 '22 at 00:53

4 Answers4

189

Yes, Blueprints are the right way to do it. What you are trying to do can be achieved like this:

Main.py

from flask import Flask
from AccountAPI import account_api

app = Flask(__name__)

app.register_blueprint(account_api)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

AccountAPI.py

from flask import Blueprint

account_api = Blueprint('account_api', __name__)

@account_api.route("/account")
def accountList():
    return "list of accounts"

If this is an option, you might consider using different URL prefixes for the different APIs/Blueprints in order to cleanly separate them. This can be done with a slight modification to the above register_blueprint call:

app.register_blueprint(account_api, url_prefix='/accounts')

For further documentation, you may also have a look at the official docs.

cyroxx
  • 3,809
  • 3
  • 23
  • 35
  • This worked perfectly for me thanks! I guess I should have read the Blueprint docs more carefeully. – user1751547 Mar 05 '13 at 18:52
  • Hey, I have a question. In following above code, does url for accountList() be matched 'domain/accounts/account'? – jeyraof Oct 12 '13 at 04:15
  • 7
    Can Main.py and AccountAPI.py have a shared global variable that is in either of the files? – matchifang Feb 03 '17 at 15:07
  • Is there a simple solution for putting `accountList` inside a class in the same file? – GA1 Jul 14 '17 at 15:36
  • Worked like a charm, further how to add protected end point by using JWT in separate .py files – Ashok Sri Jun 25 '19 at 04:08
  • @AshokSri This goes beyond the scope of the question. I would recommend to search for a good tutorial on Flask and JWT. – cyroxx Jul 25 '19 at 17:04
55

Using Blueprint you can add your routes in the routes directory.

Structure

app.py
routes
    __init__.py
    index.py
    users.py

__init__.py

from flask import Blueprint
routes = Blueprint('routes', __name__)

from .index import *
from .users import *

index.py

from flask import render_template
from . import routes

@routes.route('/')
def index():
    return render_template('index.html')

users.py

from flask import render_template
from . import routes

@routes.route('/users')
def users():
    return render_template('users.html')

app.py

from routes import *
app.register_blueprint(routes)

If you want to add a new route file, say accounts.py, you just need to create the file accounts.py in the routes directory, just like index.py and users.py, then import it in the routes.__init__.py file

from .accounts import *
Searene
  • 25,920
  • 39
  • 129
  • 186
4

If you are using blueprints and want to route / redirect to a url of your blueprint inside a template you are using you need to use the correct url_for statement.

In your case if you would like to open the url account of your blueprint you have to state it like this in your template:

href="{{ url_for('account_api.account') }}"

and for the main app it would look like this:

redirect(url_for('account_api.account'))

Otherwise the werkzeug library will throw an error.

Dušan Maďar
  • 9,269
  • 5
  • 49
  • 64
Thomas Krickl
  • 101
  • 1
  • 3
1

One another way to do this can be with lazy loading, where you would explicitly attach view functions on need basis.

New Alexandria
  • 6,951
  • 4
  • 57
  • 77
Bhaskar
  • 281
  • 3
  • 8