I wanted to deploy an app made with Flask to a production environment. It wasn't easy, and I ended up facing the whole day. When I was doing it with Rails, it started up instantly with git push heroku master
from heroku create
.
That's why I will leave a memorandum until Flask is launched on Heroku.
Click here for the technology used for deployment this time.
In the Flask tutorial, the DB is created with the db.create_all ()
command. However, for those who are accustomed to so-called migration files, it is still desirable to manage the state of the table. In that case, use Flask Migrate
.
First of all, we will do the initial construction of the application. Flask is quite customizable, so different developers have different directory structures. I'm still looking for best practices, but in the end it looks like this.
app/
├── manage.py
├── main
│ ├── __init__.py
│ ├── views.py
│ ├── config.py
│ ├── models.py
│ ├── app.db
│ ├── static/
│ ├── templates/
│ └── instance
│ └──application.cfg
├── Procfile
├── requirements.txt
├── migrations/
└── venv/
$ cd APP
$ mkdir -p main/{static,templates,instance}
$ cd main
$ touch manage.py requirements.txt Procfile
$ touch main/{__init__,views,models,config}.py
Add style sheets and view parts as you like. This time, the DB works properly on Heroku, and I will do it until "Hello world!" Is issued, so only the back end.
manage.py A file to start and run flask.
manage.py
from main import app
app.run()
main/init.py Generate flask app.
main/__init__.py
from flask import Flask
app = Flask(__name__)
import main.views
main/views.py The view part that displays Hello world !.
main/views.py
from flask import render_template
from main import app, db
@app.route('/')
def home():
return render_template('home/index.html')
There are many articles on best practices around here, so I thought it would be easier to understand if you refer to them. Here, I will introduce the ones that can hide the secrets once they move.
main/config.py
main/config.py
import os
class BaseConfig(object):
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(BaseConfig):
DEBUG = True
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db'
class ProductionConfig(BaseConfig):
DEBUG = True
TESTING = True
SQLALCHEMY_DATABASE_URI=os.environ.get('DATABASE_URL')
config = {
"default": "main.config.BaseConfig",
"development": "main.config.DevelopmentConfig",
"production": "main.config.ProductionConfig",
}
def configure_app(app):
config_name= os.getenv('FLASK_ENV')
app.config.from_object(config[config_name])
app.config.from_pyfile('application.cfg', silent=True)
** FLASK_ENV ** should be set as ʻexport FLASK_ENV = development`. What I'm saying here is that while the basic BaseConfig contents are used in common, the variable contents are separated according to the environment (development / production).
ʻOs.environ.get ('DATABASE_URL')` will automatically pull ** DATABASE_UEL ** to the database on Heroku, so set this for production.
main/instance/application.cfg
instance/application.cfg
SECRET_KEY='XXXXXXXXXXXXXXXXXXX'
Here, API keys that cannot be made public are listed. Also, be sure to write it in .gitignore
and do not publish it.
Make the prepared configuration file available in __init__.py
.
main/__init__.py
#Add the following contents
from main.config import configure_app
app = Flask(__name__, instance_relative_config=True)
configure_app(app)
Deploy to Heroku and install two libraries to use PostgreSQL
.
$ pip install gunicorm
$ pip install psycopg2
Add commands to run the app on heroku.
web: gunicorn main:app --log-file -
pip freeze
is a convenient command that lists all the library information used in the virtual environment.
$ pip freeze > requirements.txt
I will omit the setting of heroku.
$ heroku create flask-app
$ git push heroku master
$ heroku config:set FLASK_APP=main
$ heroku config:set FLASK_ENV=production
At this point, if you do $ heroku open
, you should see" Hello world! ".
This time, we will prepare the ʻUser` model as a test.
main/models.py
from main import db
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
email = db.Column(db.String, unique=True)
def __repr__(self):
return '<User %r>' % self.name
Install each library required to migrate the DB.
$ pip install flask_migrate
$ pip install flask_sqlalchemy
Add the preparation for loading the set model to __init__.py
.
main/__init__.py
#I will add the following
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
db = SQLAlchemy(app)
migrate = Migrate(app, db)
db.init_app(app)
import main.models
Migrate according to the Flask Migrate command.
$ flask db init
$ flask db migrate
$ flask db upgrade
Doing this will generate a migrations
file and a database called ʻapp.db`.
As before, set up the newly installed library for use on Heroku.
$ pip freeze > requirements.txt
I'm a little addicted to this, but for Heroku, I'll give the locally generated migrations
files to the server and not run db init
or db migrate
.
$ heroku run flask db upgrade
Recommended Posts