Composition of views and models
As our application becomes bigger, we might want to structure it in a modular manner. In this recipe, we will do this by restructuring our Hello World application.
How to do it...
First, create a new folder in the application and move all the files inside this new folder. Then, create __init__.py
in the folders, which are to be used as modules.
After that, create a new file called run.py
in the topmost folder. As its name implies, this file will be used to run the application.
Finally, create separate folders to act as modules.
Refer to the following file structure to get a better understanding:
flask_app/ run.py my_app/ __init__.py hello/ __init__.py models.py views.py
Let’s see how each of the preceding files will look.
The flask_app/run.py
file will look something like the following lines of code:
from my_app import app app.run(debug=True)
The flask_app/my_app/__init__.py
file will look something like the following lines of code:
from flask import Flask app = Flask(__name__) import my_app.hello.views
Next, we have an empty file just to make the enclosing folder a Python package, flask_app/my_app/hello/__init__.py
:
# No content. # We need this file just to make this folder a python module.
The models file, flask_app/my_app/hello/models.py
, has a non-persistent key-value store, as follows:
MESSAGES = { 'default': 'Hello to the World of Flask!', }
Finally, the following is the views file, flask_app/my_app/hello/views.py
. Here, we fetch the message corresponding to the requested key and can also create or update a message:
from my_app import app from my_app.hello.models import MESSAGES @app.route('/') @app.route('/hello') def hello_world(): return MESSAGES['default'] @app.route('/show/<key>') def get_message(key): return MESSAGES.get(key) or "%s not found!" % key @app.route('/add/<key>/<message>') def add_or_update_message(key, message): MESSAGES[key] = message return "%s Added/Updated" % key
How it works...
In this recipe, we have a circular import between my_app/__init__.py
and my_app/hello/views.py
, where, in the former, we import views
from the latter, and in the latter, we import app
from the former. Although this makes the two modules dependent on each other, there is no issue, as we won’t be using views in my_app/__init__.py
. Note that it is best to import the views at the bottom of the file so that they are not used in this file. This ensures that when you refer to the app
object inside the view, it does not lead to null-pointer exceptions.
In this recipe, we used a very simple non-persistent in-memory key-value store to demonstrate the model’s layout structure. We could have written the dictionary for the MESSAGES
hash map in views.py
itself, but it is best practice to keep the model and view layers separate.
So, we can run this app using just run.py
, as follows:
$ python run.py Serving Flask app "my_app" (lazy loading) Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. Debug mode: on Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) Restarting with stat Debugger is active! * Debugger PIN: 111-111-111
Tip
Note the preceding WARNING
in the block. This warning occurs because we did not specify the application environment, and by default, production
is assumed. To run the application in the development
environment, modify the run.py
file with the following:
from my_app
import app
app.env="development"
app.run(debug=True)
Information
The reloader indicates that the application is being run in debug mode and that the application will reload whenever a change is made in the code.
As we can see, we have already defined a default message in MESSAGES
. We can view that by opening http://127.0.0.1:5000/show/default
. To add a new message, we can type http://127.0.0.1:5000/add/great/Flask%20is%20greatgreat!!
. This will update the MESSAGES
key-value store so that it looks like this:
MESSAGES = { 'default': 'Hello to the World of Flask!', 'great': 'Flask is great!!', }
Now, if we open http://127.0.0.1:5000/show/great
in a browser, we will see our message, which would have otherwise appeared as a not found message.
See also
The next recipe, Creating a modular web app with blueprints, provides a much better way of organizing your Flask applications and is a ready-made solution for circular imports.