Flask Configurations
This introductory chapter will help us to understand the different ways Flask can be configured to suit various needs as per the demands of the project.
So, why a microframework? Does this mean Flask lacks functionality, or that it's mandatory your complete web application goes inside one file? Not really! The microframework simply refers to the fact that Flask aims to keep the core of its framework small but highly extensible. This makes writing applications or extensions both easy and flexible, and gives developers the power to choose the configurations they want for their application without imposing any restrictions on the choice of database, templating engine, and so on. In this chapter, you will learn a number of ways to set up and configure Flask.
Getting started with Flask takes just a couple of minutes. Setting up a simple Hello World application is as easy as pie. Simply create a filename, such as app.py—in any location on your computer that can access python—that contains the following script:
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello to the World of Flask!' if __name__ == '__main__': app.run()
Now, Flask needs to be installed; this can be done via pip or pip3. You may have to use sudo on a Unix-based machine if you run into access issues:
$ pip3 install Flask
The preceding snippet is a complete Flask-based web application. Here, an instance of the imported Flask class is a Web Server Gateway Interface (WSGI) (http://legacy.python.org/dev/peps/pep-0333/) application. So, app in this code becomes our WSGI application, and as this is a standalone module; we set the __name__ string as '__main__'. If we save this in a file with the name app.py, then the application can simply be run using the following command:
$ python3 app.py * Running on http://127.0.0.1:5000/
Now, if we head over to our browser and type http://127.0.0.1:5000/, we can see our application running.
Alternatively, the application can also be run by using flask run or by using Python's -m switch with Flask. While following this approach, the last two lines of app.py can be skipped. Note that the following commands work only if there is a file named app.py or wsgi.py in the current directory. If not, then the file containing the app object should be exported as an environment variable, such as FLASK_APP. As a best practice, this should be done in either case:
$ export FLASK_APP=app.py
$ flask run
* Running on http://127.0.0.1:5000/
Alternatively, if you decide to use the -m switch, it will look as follows:
$ export FLASK_APP=app.py
$ python3 -m flask run
* Running on http://127.0.0.1:5000/
In this chapter, we will cover the following recipes:
- Setting up our environment with virtualenv
- Handling basic configurations
- Configuring class-based settings
- Organizing static files
- Being deployment-specific with instance folders
- Compositions of views and models
- Creating a modular web app with Blueprints
- Making a Flask app installable using setuptools
Setting up our environment with virtualenv
Flask can be simply installed using pip/pip3 or easy_install globally, but it's preferable to set up an application environment using virtualenv. This prevents the global Python installation from being affected by a custom installation, as it creates a separate environment for the application. This separate environment is helpful as it allows you to have multiple versions of the same library used for multiple applications; some packages might also have different versions of the same libraries as dependencies. virtualenv manages this in separate environments and does not let the incorrect version of any library affect any application. In this recipe, we will learn about how to create and manage these environments.
How to do it...
First, install virtualenv using pip3 and then create a new environment with the name my_flask_env inside the folder in which we ran the first command. This will create a new folder with the same name, as follows:
$ pip3 install virtualenv $ virtualenv my_flask_env
Run the following commands from inside the my_flask_env folder:
$ cd my_flask_env $ source bin/activate $ pip3 install flask
This will activate our environment and install Flask inside it. Now, we can do anything with our application within this environment, without affecting any other Python environment.
How it works...
So far, we have used pip3 install flask multiple times. As the name suggests, the command refers to the installation of Flask, just like any Python package. If we look a bit deeper into the process of installing Flask via pip3, we will see that a number of packages are installed. The following is an outline of the package installation process of Flask:
$ pip3 install -U flask Downloading/unpacking flask ........... ........... Many more lines......... ........... Successfully installed flask Werkzeug Jinja2 itsdangerous
markupsafe click Cleaning up...
If we look carefully at the preceding snippet, we will see that there are six packages installed in total; namely, flask, Werkzeug, Jinja2, click, itsdangerous, and markupsafe. These are the packages on which Flask depends, and it will not work if any of them are missing.
There's more...
To make our lives easier, we can use virtualenvwrapper, which, as the name suggests, is a wrapper written over virtualenv and makes the handling of multiple instances of virtualenv easier.
Remember that the installation of virtualenvwrapper should be done on a global level. So, deactivate any virtualenv that might still be active. To deactivate, use the following command:
$ deactivate
Install virtualenvwrapper using the following commands:
$ pip3 install virtualenvwrapper $ export WORKON_HOME=~/workspace $ source /usr/local/bin/virtualenvwrapper.sh
In the preceding code, we installed virtualenvwrapper, created a new environment variable with the name WORKON_HOME, and provided it with a path, which will act as the home for all virtual environments created using virtualenvwrapper.
To create a virtualenv and install Flask, use the following commands:
$ mkvirtualenv my_flask_env $ pip3 install flask
To deactivate a virtualenv, simply run the following command:
$ deactivate
To activate an existing virtualenv using virtualenvwrapper, run the following command:
$ workon my_flask_env
See also
The references and installation links relating to this section are as follows:
Handling basic configurations
When we configure a Flask application, we're able to do so as per the need. So, in this recipe, we will try to understand the different ways in which Flask can be configured, including how to load a configuration from environment variables, Python files, or even a config object.
Getting ready
In Flask, a configuration is done on an attribute named config of the Flask object. The config attribute is a subclass of a dictionary, and we can modify it just like any dictionary.
How to do it...
To run our application in the debug mode, for instance, we can write the following:
app = Flask(__name__) app.config['DEBUG'] = True
app.debug = True
Alternatively, we can pass debug as a named argument to app.run, as follows:
app.run(debug=True)
In new versions of Flask, the debug mode can also set on an environment variable, FLASK_DEBUG=1, and then run the app using flask run or Python's -m switch:
$ export FLASK_DEBUG=1
Enabling the debug mode will make the server reload itself in the event of any code changes, and it also provides the very helpful Werkzeug debugger when something goes wrong.
There are a bunch of configuration values provided by Flask. We will come across them in relevant recipes throughout this chapter.
As an application grows larger, there is a need to manage the application's configuration in a separate file, as shown in the following example. Mostly specific to machine-based setups, it is unlikely that this will be a part of the version-control system. For this, Flask provides us with multiple ways to fetch configurations. The most frequently used methods are as follows:
- From a Python configuration file (*.cfg), the configuration can be fetched using the following command:
app.config.from_pyfile('myconfig.cfg')
- From an object, the configuration can be fetched using the following command:
app.config.from_object('myapplication.default_settings')
- Alternatively, to load from the same file from which this command is run, we can also use the following command:
app.config.from_object(__name__)
- From the environment variable, the configuration can be fetched using the following command:
app.config.from_envvar('PATH_TO_CONFIG_FILE')
How it works...
Flask is intelligent enough to pick up only configuration variables that are written in uppercase. This allows us to define any local variables in our configuration files and objects and leave the rest to Flask.
The best practice when using configurations is to have a bunch of default settings in app.py, or via any object in the application itself, and to then override the same by loading it from the configuration file. So, the code will look as follows:
app = Flask(__name__) DEBUG = True TESTING = True app.config.from_object(__name__) app.config.from_pyfile('/path/to/config/file')
Configuring using class-based settings
An interesting way of laying out configurations for different deployment modes, such as production, testing, staging, and so on, can be cleanly done using the inheritance pattern of classes. As your project gets bigger, you can have different deployment modes, such as development, staging, production, and so on, where each mode can have several different configuration settings, or some settings that will remain the same. In this recipe, we will learn how to use class-based settings to achieve such a pattern.
How to do it...
We can have a default setting base class, and other classes can inherit that base class and override or add deployment-specific configuration variables to it, as shown in the following example:
class BaseConfig(object): 'Base config class' SECRET_KEY = 'A random secret key' DEBUG = True TESTING = False NEW_CONFIG_VARIABLE = 'my value' class ProductionConfig(BaseConfig): 'Production specific config' DEBUG = False SECRET_KEY = open('/path/to/secret/file').read() class StagingConfig(BaseConfig): 'Staging specific config' DEBUG = True class DevelopmentConfig(BaseConfig): 'Development environment specific config' DEBUG = True TESTING = True SECRET_KEY = 'Another random secret key'
How it works...
Now we can use any of the preceding classes while loading the application's configuration via from_object(). Let's say that we save the preceding class-based configuration in a file named configuration.py, as follows:
app.config.from_object('configuration.DevelopmentConfig')
Overall, this makes the management of configurations for different deployment environments more flexible and easy.
Organizing static files
Organizing static files such as JavaScript, stylesheets, images, and so on efficiently is always a matter of concern for all web frameworks. In this recipe, we'll learn how to achieve this in Flask.
How to do it...
Flask recommends a specific way of organizing static files in an application, as follows:
my_app/ - app.py - config.py - __init__.py - static/ - css/ - js/ - images/ - logo.png
While rendering this in templates (say, the logo.png file), we can refer to the static files using the following code:
<img src='/static/images/logo.png'>
How it works...
If a folder named static exists at the application's root level, that is, at the same level as app.py, then Flask will automatically read the contents of the folder without any extra configuration.
There's more...
Alternatively, we can provide a parameter named static_folder to the application object while defining the application in app.py, as follows:
app = Flask(__name__, static_folder='/path/to/static/folder')
In the preceding line of code, static refers to the value of static_url_path on the application object. This can be modified as follows:
app = Flask( __name__, static_url_path='/differentstatic', static_folder='/path/to/static/folder' )
Now, to render the static file, we will use the following code:
<img src='/differentstatic/logo.png'>
It is always a good practice to use url_for to create URLs for static files rather than explicitly defining them, as follows:
<img src="{{ url_for('static', filename='logo.png') }}">
Being deployment-specific with instance folders
Flask provides yet another method for configuration, where we can efficiently manage deployment-specific parts. Instance folders allow us to segregate deployment-specific files from our version-controlled application. We know that configuration files can be separate for different deployment environments, such as development and production, but there are also many more files, such as database files, session files, cache files, and other runtime files. In this recipe, we will create an instance folder, which will act like a holder bin for such kinds of files.
How to do it...
By default, the instance folder is picked up from the application automatically if we have a folder named instance in our application at the application level, as follows:
my_app/ - app.py - instance/ - config.cfg
We can also explicitly define the absolute path of the instance folder using the instance_path parameter on our application object, as follows:
app = Flask( __name__, instance_path='/absolute/path/to/instance/folder' )
To load the configuration file from the instance folder, we will use the instance_relative_config parameter on the application object, as follows:
app = Flask(__name__, instance_relative_config=True)
This tells the application to load the configuration file from the instance folder. The following example shows how this will work:
app = Flask( __name__, instance_path='path/to/instance/folder', instance_relative_config=True ) app.config.from_pyfile('config.cfg', silent=True)
How it works...
In the preceding code, first, the instance folder is loaded from the given path, and then, the configuration file is loaded from the file named config.cfg in the given instance folder. Here, silent=True is optional and is used to suppress the error if config.cfg is not found in the instance folder. If silent=True is not given and the file is not found, then the application will fail, giving the following error:
IOError: [Errno 2] Unable to load configuration file (No such file
or
directory): '/absolute/path/to/config/file'
Composition of views and models
As our application grows 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 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 the 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 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 will 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...
We can see that 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 the 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 recipe, we used a very simple non-persistent in-memory key-value store for the demonstration of the model layout structure. It is true that 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
from my_app import app
app.env="development"
app.run(debug=True)
We can see that we have already defined a default message in MESSAGES. We can view the 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 to look like the following:
MESSAGES = { 'default': 'Hello to the World of Flask!', 'great': 'Flask is great!!', }
Now, if we open the link http://127.0.0.1:5000/show/great link 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.
Creating a modular web app with blueprints
A blueprint is a concept in Flask that helps make large applications really modular. This keeps application dispatching simple by providing a central place to register all components in an application. A blueprint looks like an application object but is not an application. It also looks like a pluggable app, or a smaller part of a bigger app, but it is not. A blueprint is actually a set of operations that can be registered on an application and represents how to construct or build an application.
Getting ready
In this recipe, we'll take the application from the previous recipe, Composition of views and models, as a reference and modify it to work using blueprints.
How to do it...
The following is an example of a simple Hello World application using Blueprint. It will work in a manner similar to the previous recipe but is much more modular and extensible.
First, we will start with the following flask_app/my_app/__init__.py file:
from flask import Flask from my_app.hello.views import hello app = Flask(__name__) app.register_blueprint(hello)
Next, the views file, my_app/hello/views.py, which should look as follows:
from flask import Blueprint from my_app.hello.models import MESSAGES hello = Blueprint('hello', __name__) @hello.route('/') @hello.route('/hello') def hello_world(): return MESSAGES['default'] @hello.route('/show/<key>') def get_message(key): return MESSAGES.get(key) or "%s not found!" % key @hello.route('/add/<key>/<message>') def add_or_update_message(key, message): MESSAGES[key] = message return "%s Added/Updated" % key
We have now defined a blueprint in the flask_app/my_app/hello/views.py file. We no longer need the application object anymore, and our complete routing is defined on a blueprint named hello. Instead of @app.route, we use @hello.route. The same blueprint is imported into flask_app/my_app/__init__.py and registered on the application object.
We can create any number of blueprints in our application and complete most of the activities that we would usually do, such as providing different template paths or different static paths. We can even have different URL prefixes or subdomains for our blueprints.
How it works...
This application will work in just the same way as the last application. The only difference is in the way the code is organized.
See also
The previous recipe, Composition of views and models, is useful for further understanding how this recipe is useful.
Making a Flask app installable using setuptools
We now have a Flask app, but how do we install it like any Python package? It is possible that another application might depend on our application, or that our application is in fact an extension for Flask and would need to be installed in a Python environment so it can be used by other applications. In this recipe, we will see how setuptools can be used to create an installable Python package.
How to do it...
Installing a Flask app can be very easily achieved using the setuptools Python library. To achieve this, create a file called setup.py in your application's folder and configure it to run a setup script for the application. This will take care of any dependencies, descriptions, loading test packages, and so on.
The following is an example of a simple setup.py script for the Hello World application:
#!/usr/bin/env python # -*- coding: UTF-8 -*- import os from setuptools import setup setup( name = 'my_app', version='1.0', license='GNU General Public License v3', author='Shalabh Aggarwal', author_email='contact@shalabhaggarwal.com', description='Hello world application for Flask', packages=['my_app'], platforms='any', install_requires=[ 'flask', ], classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License v3', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules' ], )
How it works...
In the preceding script, most of the configuration is self-explanatory. The classifiers are used when the application is made available on PyPI. These will help other users search the application using the relevant classifiers.
Now, we can run this file with the install keyword, as follows:
$ python setup.py install
The preceding command will install the application along with all the dependencies mentioned in install_requires, that is, Flask and all of Flask's dependencies. Now the app can be used just like any Python package in a Python environment.
See also
The list of valid trove classifiers can be found at https://pypi.python.org/pypi?%3Aaction=list_classifiers.