/flask-heroku

Basic template for a Flask app on Heroku

Primary LanguagePython

Flask Boilerplate

Introduction

This project serves as a quickstart for a Flask project. It also is compatible with Heroku, so you can deploy it directly, or run it standalone in your own set up

Structure

.
├── acme/
│   ├── widget/
│   │   ├── __init__.py
│   │   ├── views.py
│   ├── db.py
│   ├── decorators.py
│   ├── __init__.py
│   ├── settings.py
├── __init__.py
├── main.py
├── Procfile
└── requirements.txt

The structure of the project is based off a single Flask app in a package (acme/) and a single Blueprint (acme/widget/)

Settings

The settings file (found in acme/settings.py) is classed-based. The variable settings.CONFIG is automatically set to eithe DevConfig or ProductionConfig, depending on whether the envvar PRODUCTION is set or not. If it is set, settings.CONFIG points to ProductionConfig. Otherwise, it points to DevConfig.

 CONFIG = ProductionConfig if bool(os.getenv("PRODUCTION", False)) else DevConfig

While configuration options can be set in settings.py, there sometimes arises occasions where overriding the defaults with envvars is desirable. To account for this, the Config objects check for any set envvars that match their own keys, and take on the value set in the envvar.

The Config objects also write their own configuration into os.environ, in order to provide for modules that insist on reading envvars instead of from a configuration file/object. The exception to this rule is the PRODUCTION key, which is never written back to the environment. This means that os.getenv('PRODUCTION') is always authoritative, and has to be set by the user.

     for k in dir(self):
        if k.isupper():
            if os.getenv(k):
                setattr(self, k, os.getenv(k))
            if k != 'PRODUCTION':
                os.environ[k] = str(getattr(self, k))

Global configuration

A common idiom in Flask is to support app-wide config settings via app.config after initialising it via app.config.from_object(settings.CONFIG) or similar. However, this means that any other module that requires access the application configuration settings needs to import app, which may be bloated, or have side-effects.

Hence, this boilerplate provides settings.CONFIG. As mentioned above, settings.CONFIG encapsulates all appropriate application settings (depending on if the app is in PRODUCTION mode or not). Once imported settings.CONFIG can be used like a dictionary, eg.

import settings
database_uri = settings.CONFIG['DB_URI']
welcome_msg = settings.CONFIG.get('WELCOME_MSG', 'Welcome to Acme Widgets')

Contributing

Thanks for reading so far! If you're using this boilerplate and run into bugs/problems, feel free to create an issue and we'll look into it. Pull requests are welcome too!