Skip to content

Instantly share code, notes, and snippets.

@mayukh18
Created September 28, 2017 19:38
Show Gist options
  • Star 76 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save mayukh18/2223bc8fc152631205abd7cbf1efdd41 to your computer and use it in GitHub Desktop.
Save mayukh18/2223bc8fc152631205abd7cbf1efdd41 to your computer and use it in GitHub Desktop.
How to setup flask app with database on heroku

Setting up flask app in heroku with a database

The below article will cover the intricacies of setting up databases and heroku in respect to a flask app. This is more like a memo and will have out of sequence instructions or solutions to errors so read thoroughly.

Setting up a database

You'll need the packages

alembic
Flask-Migrate
Flask-Script
Flask-SQLAlchemy
psycopg2

Now. Information. alembic will install on its own if you install the 3 packages after it. You'll need psycopg2 ONLY IF you plan on deploying to heroku and using their database.

You'll need at least 3 files to use migration and other features of flask-migrate

Bare minimum files

  1. models.py
from manage import db,app

class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)

    def __repr__(self):
        return '<User %r>' % (self.nickname)
  1. app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'

db = SQLAlchemy(app)

from models import User

@app.route('/add/')
def webhook():
    name = "ram"
    email = "ram@ram.com"
    u = User(id = id, nickname = name, email = email)
    print("user created", u)
    db.session.add(u)
    db.session.commit()
    return "user created"

@app.route('/delete/')
def delete():
    u = User.query.get(i)
    db.session.delete(u)
    db.session.commit()
    return "user deleted"

if __name__ == '__main__':
    app.run()
  1. manage.py
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

from app import app, db

migrate = Migrate(app, db)

manager = Manager(app)
manager.add_command('db', MigrateCommand)


if __name__ == '__main__':
    manager.run()

NOTE: Where we are importing what. In app.py we are importing User after we declare db since that is used in models, from where User is imported.

Database configuration params

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'

This sets up the parameter SQLALCHEMY_DATABASE_URI and tells it to point to a sqlite db. This can also be declared in a config.py file and then in app.py

app.config.from_object('config')

flask-migrate

Initialize the database and create the migrations folder.

Force flask-migrate to detect changes in data types of columns

Check [https://stackoverflow.com/questions/17174636/can-alembic-autogenerate-column-alterations]

The above one worked. But very importantly also check [https://stackoverflow.com/questions/33944436/flask-migrate-and-changing-column-type]

Deploying on Heroku

Heroku has a free hobby development database that we can use happily. Let's see how we can set up the database, link it to our app and do the necessary stuff keeping most of our hair intact.

Step 1

psycopg2 required from here on.

Go to this [https://devcenter.heroku.com/articles/getting-started-with-python#provision-a-database]

Also check this out [https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xviii-deployment-on-the-heroku-cloud]

Do note the above link is outdated in regards to the command given for adding a database. It is now hobby-dev not dev. Also we don't need to promote now. It will already be promoted to DATABASE_URL

Run the below command on terminal.

heroku addons:add heroku-postgresql:hobby-dev

Step 2

2.1. Now we'll face some problem regarding migrating. What we'll do is below in order to bypass the problems.

heroku run python
>> import os
>> os.environ.get('DATABASE_URL')

It will give the link to the development database on Heroku. (It will be something like postgres://bllahblah)

2.2. Replace the value of DATABASE_URI in config.py with this value.

**2.3.**Then do apply your changes to Heroku database.

python manage.py db init
python manage.py db migrate
python manage.py db upgrade

Then push your code as usual. Better push your migrations on Heroku too. Don't leave your migrations folder out of git commit. But keep local sqlite db outside.

Step 3 | Procfile

web: python manage.py runserver --host 0.0.0.0 --port ${PORT}
init: python manage.py db init
migrate: python manage.py db migrate
upgrade: python manage.py db upgrade

This is how the Procfile MUST look like. We don't care much about the last 3. The first one is what is very very important. Notice in app.py we a calling app.run() without any parameters (host and port). It should be that way because we'll be delivering the host and port from here in Procfile. DON'T PUT THE PARAMETERS INSIDE app.py EVEN IF YOU KNOW THOSE VALUES WELL. If it is not like this, the app won't be able to launch after each push and deploy.

Btw, we call Procfile commands using Heroku CLI from terminal this way

heroku run init
heroku run migrate
heroku run web

This also can be done without calling the aliases

heroku run python manage.py db init

To go into the heroku shell

heroku run bash

ls -ltr shows the directory structure, exit closes the bash terminal.

ERROR: alembic.util.CommandError: can't find identifier

[https://stackoverflow.com/questions/32311366/alembic-util-command-error-cant-find-identifier]

Do what is said in the SO thread. You'll need to install PostgreSQL first.

Go to this link [https://devcenter.heroku.com/articles/heroku-postgresql#set-up-postgres-on-windows]

Be sure to close everything on mother earth after updating th PATH variable. If everything was correct, you'll be able to call psql on terminal. Then do

heroku pg:psql

You'll then go into the db shell of the heroku database. Now write the commands as instructed in the SO answer and do the rest.

NOTE: If psql asks for password, the password you set up during install won't work. Check the SO thread [https://stackoverflow.com/questions/12562928/psql-exe-password-authentication-failed-in-windows]

@datlife
Copy link

datlife commented Dec 1, 2018

Great writeup. Thanks, mayukh18!

@thiagocom
Copy link

Thanks

@Rasoolaghd
Copy link

very helpful!

@ByK95
Copy link

ByK95 commented Jun 5, 2020

I was in the edge of loosing it then i found this. 🙏

@SweetWeakness
Copy link

Dude thnx

@XYTYX
Copy link

XYTYX commented Oct 5, 2020

holy SHIT dude you're a g thank you so much

@goodnewsj62
Copy link

thanks, just saved me a large headache

@Victor7095
Copy link

Victor7095 commented Feb 5, 2021

Is there any way tu upgrade automatically? Like:

from flask_migrate import Migrate, upgrade
...
app = Flask(__name__)
migrate = Migrate(app, db)
upgrage()

@cd-eha
Copy link

cd-eha commented Dec 30, 2021

Here is another solution I've found reddit to run automaticaly a post-compilation script :

  1. Create a bin folder inside the app root folder
  2. Create a file named post_compile
  3. Then put inside it the script you wanna run after the deploy. Eg: flask db init && flask db migrate && flask db upgrade
$ mkdir bin
$ echo "flask db init && flask db migrate && flask db upgrade" > bin/post_compile

@forever585
Copy link

Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment