-
Notifications
You must be signed in to change notification settings - Fork 102
New Project With Django, Python and Heroku
this github repository does a much better job at explaining things: https://github.com/etianen/django-herokuapp
- https://www.apple.com/au/macbook-pro/
- https://www.heroku.com/
- https://github.com/
- http://brew.sh/
- Python 2.7:
brew install python
- http://postgresapp.com/ Make sure you can run the Postgres executables:
pg_config
# ....
Otherwise add /Applications/Postgres.app/Contents/Versions/{version}/bin/
to your path
- https://virtualenvwrapper.readthedocs.org/en/latest/
- https://toolbelt.heroku.com/
- https://github.com/kennethreitz/autoenv
${PROJECT}
is the name of your project for all of the steps below
- New repository on Github: https://github.com/new
- New Virtual Environment:
mkvirtualenv ${PROJECT}
cdvirtualenv
git clone https://github.com/mattharley/${PROJECT}.git
cd ${PROJECT}
Warning: If you clone with https it is very difficult to then switch over to an SSH connection!! If you intend to use SSH then clone with SSH...
- Install the [essentials](Web App Development Essentials)
TODO - update to
whitenoise
instead ofdj-static
easy_install readline # only for OSX?
pip install Django dj-database-url dj-static django-debug-toolbar django-nose django-redis gunicorn ipdb ipython mock newrelic nose psycopg2 pytz python-dateutil redis requests static
pip freeze > requirements.txt
Remember: This is in the PROJECT location(i.e. <YourProjects/ProjectVirtualEnv/ProjectName>)
- Create our project and app
django-admin startproject ${PROJECT}_project
django-admin startapp ${PROJECT}
- I prefer to have the directly laid out like this...
mv ${PROJECT}_project ${PROJECT}_project_parent
mv ${PROJECT}_project_parent/* .
rm -rf ${PROJECT}_project_parent/
- Create Heroku apps
heroku apps:create ${PROJECT}
heroku apps:create ${PROJECT}-test
git remote add heroku-test [email protected]:${PROJECT}-test.git
- setup local environment variables in your .env file (for autoenv)
Remember: This is in the PROJECT location(i.e. <YourProjects/ProjectVirtualEnv/ProjectName>)
# .env
# Switch debug on and also now we can refer to test at $T and production at $P
export DEBUG=True
export PROJECT=${PROJECT}
export T='--app='${PROJECT}'-test'
export P='--app='${PROJECT}
- Activate environment variables
cd .. && cd ${PROJECT}
- Awesome Heroku Settings Template
First of all take the value of
SECRET_KEY
out of the original settings file - we don't want to check that into source control! Instead, we'll make it an environment variable (see below)
Here's what your settings file should look like:
# ${PROJECT}_project/settings.py
import sys
import os
import urlparse
from django.core.exceptions import ImproperlyConfigured
def get_env_variable(var_name, default=None):
""" Get the environment variable or return exception """
try:
return os.environ[var_name]
except KeyError:
if default is not None:
return default
else:
error_msg = "Set the %s environment variable" % var_name
raise ImproperlyConfigured(error_msg)
PROJECT_PATH = os.path.abspath(os.path.dirname(__name__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = get_env_variable("SECRET_KEY", "")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = bool(get_env_variable("DEBUG", False))
if DEBUG:
DEBUG_TOOLBAR_PATCH_SETTINGS = True
else:
DEBUG_TOOLBAR_PATCH_SETTINGS = False
TEMPLATE_DEBUG = DEBUG
ALLOWED_HOSTS = [
'127.0.0.1',
'localhost',
'${PROJECT}.herokuapp.com',
'${PROJECT}-test.herokuapp.com',
]
# Application definition
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_nose',
'${PROJECT}',
'debug_toolbar',
'django.contrib.admin',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
)
ROOT_URLCONF = '${PROJECT}_project.urls'
WSGI_APPLICATION = '${PROJECT}_project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': '${PROJECT}',
'USER': '',
'PASSWORD': '',
'HOST': 'localhost', # Note on Ubuntu the presence of these two lines can cause problems
'PORT': '', # with passwordless logins. It's safe to remove them.
}
}
HEROKU = bool(os.environ.get('DATABASE_URL'))
if HEROKU:
import dj_database_url
DATABASES['default'] = dj_database_url.config()
DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
DEBUG_TOOLBAR_PATCH_SETTINGS = False
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': 'cache.sqlite',
},
}
redis_url = None
if os.environ.get('REDISCLOUD_URL'):
redis_url = urlparse.urlparse(os.environ.get('REDISCLOUD_URL'))
CACHES = {
'default': {
"BACKEND": "redis_cache.cache.RedisCache",
'LOCATION': '{0.hostname}:{0.port}:0'.format(redis_url),
'OPTIONS': {
'PASSWORD': redis_url.password,
'CLIENT_CLASS': 'redis_cache.client.DefaultClient',
},
},
}
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_ROOT = 'static/'
STATIC_URL = '/static/'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'formatters': {
'verbose': {
'format': '[%(levelname)s] [%(module)s %(funcName)s] [p%(process)d t%(thread)d] %(message)s'
},
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'stream': sys.stdout,
'formatter': 'verbose'
},
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
},
'null': {
'level': 'DEBUG',
'class':'django.utils.log.NullHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['null'], # Quiet by default!
'propagate': False,
'level':'DEBUG',
},
'analytics': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True,
},
'${PROJECT}': {
'handlers': ['console'],
'level': 'DEBUG',
'propogate': True,
},
'django.request': {
'handlers': ['console'],
'level': 'DEBUG',
'propogate': True,
}
},
}
from django.core.signals import got_request_exception
import traceback
import logging
logger = logging.getLogger(__name__)
def exception_printer(sender, **kwargs):
logger.error(''.join(traceback.format_exception(*sys.exc_info())))
got_request_exception.connect(exception_printer)
- Set the secret key as an environment variable.
echo -e "export SECRET_KEY='${YOUR_SECRET_KEY}'\n" >> .env
cd .. && cd ${PROJECT}
heroku config:set SECRET_KEY=${YOUR_SECRET_KEY} $P
# TODO: this should probably be a different secret key
heroku config:set SECRET_KEY=${YOUR_SECRET_KEY} $T
If you need to generate a temporary secret key for local dev (say you're joining a project which is already using a secret key on Heroku that you can't access), you can use this tool. You can prefix it with something that reminds you that it is in fact a temporary key. Then just add it to your .env without pushing it up to heroku.
- Database setup
createdb ${PROJECT}
createdb ${PROJECT}-test
chmod +x ./manage.py
./manage.py syncdb
- Django Static Files
# ${PROJECT}_project/wsgi.py
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "${PROJECT}_project.settings")
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
application = Cling(get_wsgi_application())
- Local test
# server
./manage.py runserver
open http://127.0.0.1:8000/admin/
* tests
./manage.py test
- Test app on Heroku: TODO: update to a app.json file
# Essential Addons
for addon in heroku-postgresql logentries:tryit newrelic:wayne rediscloud; do heroku addons:add $addon $T; done
for addon in heroku-postgresql logentries:tryit newrelic:wayne rediscloud; do heroku addons:add $addon $P; done
# Procfile
echo -e "web: newrelic-admin run-program gunicorn "${PROJECT}"_project.wsgi -w 4 --log-level DEBUG\n" > Procfile
- Push to Test Server
# Firstly enable DEBUG on the Test Server
heroku config:set DEBUG=True $T
git add .
git commit -m 'setup django project'
git push heroku-test master
heroku run "./manage.py syncdb && ./manage.py migrate" $T
open http://${PROJECT}-test.herokuapp.com/admin/