How to use this project
Create a new directory for your project and do a git checkout
mkdir -p /path/to/project && cd /path/to/project
git clone [email protected]:hartleybrody/flask-boilerplate.git
Then you can move the files out of the flask-boilerplate
directory and into /path/to/project
using
cp -r flask-boilerplate/. .
Finally, delete the flask-boilerplate
directory and start it as a new git repo
rm -rf flask-boilerplate
rm -rf .git && git init
git add .
git commit -m "initial import from flask boilerplate"
To make this template fit your app, replace the following
- {{APP_NAME}} -> App Name
- {{APP_SLUG}} -> app-name
- {{APP_BLURB}} -> Here is a quick blurb about the app
=====================
{{APP_BLURB}}
If this is the first time you're setting up the project, you'll need to create a new virtual environment for it.
mkvirtualenv {{APP_SLUG}}
This project assumes you already have autoenv installed globally on your system.
brew install autoenv
The first time you cd
into the project directory, autoenv will ask your permission to source the .env
file.
Note that while .env
is initially provided for you, any configuration information you put in there should NOT be committed. Let's remove it from git tracking.
git rm -r --cached .env
Once it's done, install the essential libraries for this project.
pip install -r requirements.txt
Optional: Once installed, you can snapshot the version of each library and override the contents of that file by pinning their version numbers. This is good practice to ensure you start your project with the latest version of each dependency, but then don't have to worry about new versions causing breaking changes down the line.
pip freeze > requirements.txt
Create the database locally
psql -h localhost -d postgres
psql (13.1)
Type "help" for help.
postgres=# CREATE DATABASE {{APP_SLUG}};
CREATE DATABASE
Once you've created a brand new database, apply the existing migrations to get your database tables setup properly
flask db upgrade
Note that the current schema is defined in models.py
and the migrations live in migrations/versions
(see below)
You'll also need to do an initial "seed" command to add some placeholder rows to the database
flask seed
Most web applications can benefit from an in-memory cache. They're great for server-side sessions and also for taking load off the database.
You can install redis using the project's Quickstart instructions.
Or, if you're on macOS with homebrew, you can simply run
brew install redis
Once you've got redis installed on your system, start the local server in the background with
redis-server --daemonize yes
Run the local flask development server (automatically reloads changes) with
flask run
or alternatively, use the production server gunicorn
gunicorn app:app --reload --bind 127.0.0.1:5000
Either way, your local development server should be viewable in a browser
http://localhost:5000
Running your local development server over SSL is optional but highly recommended since it makes your local env closer to prod, and allows you to catch potential content issues sooner. I recommend mkcert for creating browser-trusted, self-signed certificates.
First, install mkcert
brew install mkcert
brew install nss
Then, allow it to install a locally-trusted CA
mkcert -install
Finally, generate a certificate for the local domain you'll be using:
mkcert {{APP_SLUG}}.local
This will generate a certificate and key in the current directory. You can move them wherever you like, just make sure to update the env variables to point to their file system location, and then uncomment out the line at the very bottom of app.py
that tells your local server to use them.
app.run(debug=True, ssl_context=(os.environ["LOCAL_SSL_CERT_PATH"], os.environ["LOCAL_SSL_KEY_PATH"]))
Alternatively, you can run your local flask development server with
flask run --cert=$LOCAL_SSL_CERT_PATH --key=$LOCAL_SSL_KEY_PATH
In order to access the local development server with the correct SSL certificates, you'll need to create an entry in your HOSTS file that points local.{{APP_SLUG}}.com
at the regular loopback interface (127.0.0.1)
On macOS, you can add an entry to your HOSTS file with:
sudo vim /etc/hosts
and then append a line to the end of the file that looks like
127.0.0.1 {{APP_SLUG}}.local
Then exit vim with the famous esc
+ :wq
and you should be able to visit the site over SSL in your browser at
https://{{APP_SLUG}}.local:5000
Once you've gotten SSL setup and running locally, you can add a "Hyper-Strict Transport Security" (HSTS) header to force the browser to always request the site over SSL. Simply uncommenting out the line in app.py that looks like
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains
WARNING: Once you uncomment this header and visit the site, your browser will always request the site over SSL for one year and there is no way to force your browser to request the site over plain ol' HTTP. This is a good security best practice, but can present a mucky situation if you haven't gotten the SSL setup stuff figured out.
Detect changes to models.py
and generate a timestamped migration file
flask db migrate
Once you've looked over the generated migrations file, apply the migration to your local database
flask db upgrade
To roll back the most recent migration that has been applied to the database (maybe due to errors or changes)
flask db downgrade
You'll need to set up a separate postgres database for testing
psql -h localhost -d postgres
psql (13.1)
Type "help" for help.
postgres=# CREATE DATABASE {{APP_SLUG}}_test;
CREATE DATABASE
To run the tests
python test.py
To push code changes to heroku
git push heroku master
To run database migrations on heroku
heroku run flask db upgrade
Make sure you run this immediately after deploying any code that includes database migrations.
============================================================
Create the frontend
docker-compose up
Note that if you make any changes to the Dockerfile or change the requirements.txt file, you'll need to "rebuild" by adding the --build
flag. You don't need to use this every time you bring the containers up though, since you can usually reuse the previously built images, which is much faster.
docker-compose up --build
DANGER: If you really, really need to burn your environment and start from scratch (say, to reinitialize the pgdata
docker volume for the database for some reason), you can run docker system prune
and then docker volume rm
the pgdata volume.
Since docker-compose specifies that the default entrypoint always starts with flask
you can run any arbitrary flask CLI command inside the docker container by passing that command to the docker-compose run web
prefix. For example:
create a migration using the docker container
docker-compose run web db migrate
run database migrations using docker
docker-compose run web db upgrade
downgrade the database using docker
docker-compose run web db downgrade
seed the database using... you get it.
docker-compose run web seed
You can follow the logs for the container with
docker logs -f {{APP_SLUG}}_web_1
You can "ssh into" a running container with
docker exec -it {{APP_SLUG}}_web_1 /bin/bash
You can inspect the database inside the container with
docker exec -it {{APP_SLUG}}_db_1 psql -U postgres
postgres=# \c {{APP_SLUG}}
You can inspect the cache inside the container with
docker exec -it {{APP_SLUG}}_cache_1 redis-cli
127.0.0.1:6379> KEYS *