Amanda
Amanda

Reputation: 12757

How to deploy / migrate an existing django app / project to a production server on Heroku?

I have a basic django app (Newsdiffs)that runs just fine at localhost:8000 with python website/manage.py runserver but I'd like to migrate it to Heroku and I can't figure out what my next step is.

I thought getting it running locally would translate to running it on Heroku, but I'm realizing that python website/manage.py runserver is launching the dev settings and I'm not sure how to tell it to use the main settings.

All that is in my Procfile is this:

web: python website/manage.py runserver

Locally, that works fine, though it launches it at http://127.0.0.1:8000/ which is probably not what I want on Heroku. So how do I figure out where to set the hostname and port? I don't see either in the app anyplace.

Upvotes: 2

Views: 2795

Answers (2)

Amanda
Amanda

Reputation: 12757

If you know some python and have a lot of experience building web apps in other languages but don't totally understand where Heroku fits, I highly recommend Discover Flask, which patched a lot of the holes in my understanding of how these pieces all fit together.

Some of the things that I worked out:

  • you really do need an isolated virtual environment if you're going to deploy to Heroku, because Heroku installs Python modules from the requirements.txt file.

  • Gunicorn is a web server, and you definitely need to run your app under Gunicorn or it won't run on Heroku.

  • The "Procfile" doesn't just give the command you use to run the app locally. And Heroku requires it. So if you've got an app that was built to run on Heroku and it doesn't include a Procfile, they left something out.

  • You don't tell Heroku what your hostname is. When you run heroku create it should tell you what your domain name is going to be. And every time you run git push heroku master (or whatever branch you're pushing, maybe it isn't master), Heroku will (try to) restart your app.

  • Heroku doesn't support sqlite. You have to run your Production DB in Postgres.

This doesn't directly answer my question, but it does fill in some of the missing pieces that were making it hard for me to even ask the right question. RTFM notwithstanding. :)

Upvotes: 2

Pynchia
Pynchia

Reputation: 11596

I have just drawn this list for myself two days ago. It was put together after having followed the steps described in Heroku's help pages for python.

It's by no means definitive nor perfect, and it will change, but it's a valid trace, since I was able to put the site online.

Some issues remain, to be checked thoroughly, e.g. the location of the media/ directory where files are uploaded should/could live outside your project for security reasons (now it works, but I have noticed if the dyno sleeps then the files are not reached/displayed by the template later). The same goes for the staticfiles/ directory (although this one seems to work fine).

Also, you might want to set django's debug mode to false.

So here it is:

My first steps to deploy an EXISTING django application to Heroku

ASSUMPTIONS:

a) your django project is in a virtual environment already

b) you have already collected all your project's required packages with

pip freeze > requirements.txt

and committed it to git

git add requirements.txt
git commit -m 'my prj requirements'

0) Activate your project's virtual environment

workon xyz  #using virtualenvwrapper

then go to your django project's directory (DPD for short) if not already taken there

cd ~/prj/xyz  (or cdproject with virtualenvwrapper if setup properly)

and create a new git branch for heroku twiddling to prevent messing things up

git checkout -b he

1) Create the app on heroku

heroku create xyz

that also adds heroku as a remote of your repo

2) Add the needed packages to requirements.txt

vi requirements.txt

add

dj-database-url==0.3.0
django-postgrespool==0.3.0
gunicorn==19.3.0
psycopg2==2.6
django-toolbelt==0.0.1
static3==0.5.1
whitenoise==2.0.3

3) Install all dependencies in the local venv

pip install -r requirements.txt --allow-all-external

4) Setup the heroku django settings

cd xyz

create a copy

cp setting.py settings_heroku.py

and edit it

vi settings_heroku.py

import os
import dj_database_url

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'), )
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

replace django's std db cfg with

DATABASES['default'] =  dj_database_url.config()
DATABASES['default']['ENGINE'] = 'django_postgrespool'

and

WSGI_APPLICATION = 'xyz.wsgi_heroku.application'

5) Configure the necessary environment variables (heroku configs)

edit the .env file

vi .env

e.g.

DJANGO_SECRET_KEY=whatever
[email protected]
EMAIL_HOST_PASSWORD=whateveritis

and/or set them manually if needed (in my case .env had no effect, wasn't loaded apparently, and had to set the vars manually for now)

heroku config:set DJANGO_SECRET_KEY=whatever
heroku config:set [email protected]
heroku config:set EMAIL_HOST_PASSWORD=whateveritis

6) Create a separate wsgi file for heroku

cd xyx
cp wsgi.py wsgi_heroku.py

and edit it to make it point to the right settings

vi wsgi_heroku.py
from whitenoise.django import DjangoWhiteNoise
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xyz.settings_heroku")
application = get_wsgi_application()
application = DjangoWhiteNoise(application) 

7) Make sure all the templates use

{% load staticfiles %}

8) Define the Procfile file so that it points to the right wsgi

e.g.

cd ~/prj/xyz (DPD)
vi Procfile

add

web: gunicorn xyz.wsgi_heroku --log-file -

9) Collect all static content into DPD/staticfiles/

locally, make sure django points to the right wsgi settings

export WSGI_APPLICATION=blogger.wsgi_heroku.application
python manage.py collectstatic

10) add the changes to the local git repo (he branch)

git add --all .
git commit -m 'first 4 heroku'

11) check the whole thing works locally

heroku local # in heroku's help they also add `web`, not needed?!

12) push your code to heroku

git push heroku he:master

13) make sure a instance of the app is running

heroku ps:scale web=1

14) create the tables on the heroku DB

heroku run python manage.py migrate

Note: if you see a message that says, “You just installed Django’s auth system, which means you don’t have any superusers defined. Would you like to create one now?”, type no.

15) add the superuser to the heroku DB

heroku run bash
python manage.py createsuperuser

and fill in the details, as usual

16) Populate the DB with the necessary fixtures

heroku run python manage.py loaddata yourfile.json

17) Visit the website page on heroku's webserver

heroku open

or go to

https://xyz.herokuapp.com/

and the admin

https://xyz.herokuapp.com/admin/

and the DB

https://xyz.herokuapp.com/db

Useful commands:

  • View the app's logs

    heroku logs [--tail]

  • List add-ons deployed

    heroku addons

    and use one:

    heroku addons:open <add-on-name>

  • Run a command on heroku (the remote env, where you are deploying)

    heroku run python manage.py shell heroku run bash

  • Set a config var on Heroku

    heroku config:set VARNAME=whatever

  • View the config vars that are set (including the DB's)

    heroku config

  • View postgres DB details

    heroku pg

Upvotes: 2

Related Questions