Install and Deploy Django app on Heroku - django

I often forget steps and wish there was a quick instructional guide on deploying a django project on Heroku.
How to Install and Deploy a Django app on Heroku?
I have posted a step-by-steps answer for steps that have worked for me.
You will get:
Django app both on heroku and your computer.
Postgres databases on both machines
git/bitbucket
authentication: login, logout, register, forgot pass, email authentication only (optional & default)
static files working on both machines
Bootstrap 3.0.3 included
South Migrations (instructions)
Requirements
heroku account
github/bitbucket account
mac with OSX (tested on 10.9)

UPDATE:
To do an installation the quick way, check out the other answer.
Folder structure
PROJECT_WRAPPER - it will hold everything, including PS
DJANGO_PROJECT - it will hold the code
DJANGO_APP - the main app will have that name
Anywhere you see those, replace with your real names!!!
Virtual Env
If you don’t have virtualenv, you need to get it. It will allow you to have separate installations of software for each project:
pip install virtualenv
then we create our project:
cd ~
mkdir PROJECT_WRAPPER && cd PROJECT_WRAPPER
virtualenv venv
now you have a dedicated folder that will contain independent installations and version of python, django, etc.
We activate and and start working on project the following way:
source venv/bin/activate
Postrges app
Just before we continue, we will install postgres.app. Grab it from:
http://postgresapp.com/
Install.
We will now hook up our environment with it:
PATH=/Applications/Postgres.app/Contents/MacOS/bin/:$PATH
Requirements.txt
Now we will need to install the following things:
Python, Django - no explanations required
South - Migrations of database (dev version of Django does not require it)
django-toolbelt - required by heroku and includes everything required for heroku
psycopg - postgres database
simplejson, mixpanel - these are optional, you could skip if you didn't like
So to create the requirements.txt file, we will get it ready from my git repository:
clone https://raw2.github.com/mgpepe/django-heroku-15/master/requirements.txt -o requirements.txt
Now with one command we will install everything from our requirements.txt:
pip install -r requirements.txt
Great, now we can verify that we have django with:
python -c "import django; print(django.get_version())"
Start a Django Project
Let’s start the project with this line and don’t forget the dot in the end:
django-admin.py startproject DJANGO_PROJECT .
Now if you type ls you should see a folder with your project name that contains your Django project.
To see if it all works run:
python manage.py runserver
DATABASE
Run the Postgres app.
Create a database with (I used my osx username):
createdb YOUR_DATABASE_NAME --owner=YOUR_OSX_USERNAME
change the DATABASES to look like this:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'YOUR_DATABASE_NAME',
'USER': 'YOUR_OSX_USERNAME',
'PASSWORD': 'YOUR_DATABASE_PASSWORD', #might be empty string ''
'HOST': '127.0.0.1',
# 'PORT': '5432',
}
}
And also let’s hook up the South migrations. Your INSTALLED_APPS should look like that:
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'south',
)
Change the SECRET_KEY variable to something else than what it is.
Now if everything was fine you should be able to create the first tables with:
python manage.py syncdb
FIRST APP
Now make your first app in your project
python manage.py startapp DJANGO_APP
in the file: ~/PROJECT_WRAPPER/DJANGO_PROJECT/settings.py
add the DJANGO_APP app to the list in the variable INSTALLED_APPS. Should look like that:
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'south',
'DJANGO_APP',
)
TEMPLATES
in settings file add the line:
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
In order for the templates to be well organized and working, we will copy base.html in one folder and the rest of templates in the app itself:
cd ~/PROJECT_WRAPPER/
mkdir templates
curl https://raw2.github.com/mgpepe/django-heroku-15/master/templates/base.html -o base.html
Now the rest of templates:
cd ~/PROJECT_WRAPPER/DJANGO_APP/
mkdir templates && cd templates
mkdir DJANGO_APP
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/changepass.html -o changepass.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/forgot_pass.html -o forgot_pass.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/home.html -o home.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/login.html -o login.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/logout.html -o logout.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/registration.html -o registration.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/splash.html -o splash.html
AUTH SYSTEM WITH EMAIL
Since it has been lately fashionable to use email instead of username, we will do that too.
*NOTE: if you decide not to use it, you can skip this step BUT you have to edit the views and templates to use username instead of email. *
In settings add the following line:
AUTHENTICATION_BACKENDS = (DJANGO_PROJECT.backends.EmailAuthBackend’,)
then copy the file backends.py in our project directory:
cd ~/PROJECT_WRAPPER/DJANGO_PROJECT/
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjangoHerokuIn15/backends.py -o backends.py
HEROKU LOCALLY
You can simulate heroku working on your computer with Foreman. Let’s create the simplest configuration file:
cd ~/PROJECT_WRAPPER
echo "web: gunicorn DJANGO_PROJECT.wsgi" > Procfile
foreman start
Now that you see it working without errors stop it with CTRL+C
in settings all the way at the bottom add:
# HEROKU
###########################
# Parse database configuration from $DATABASE_URL
if os.environ.has_key('DATABASE_URL'):
import dj_database_url
DATABASES['default'] = dj_database_url.config()
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Allow all host headers
ALLOWED_HOSTS = ['*']
In your DJANGO_PROJECT/wsgi.py file and add the following to bottom:
from dj_static import Cling
application = Cling(get_wsgi_application())
STATIC FILES
Ideally you would server static files from Amazon or something like that. But for simple sites you could use Django. Setting it up requires you to append this in settings file:
# HEROKU STATIC ASSETS CONFIGURATION
################################
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = 'staticfiles'
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
and put all static files in a specific folder. First go to your project folder with something like:
cd ~/PROJECT_WRAPPER/DJANGO_PROJECT/
and now you can just copy/paste the rest:
mkdir static && cd static
mkdir css && cd css
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjangoHerokuIn15/static/css/bootstrap.min.css -o bootstrap.min.css
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjangoHerokuIn15/static/css/styles.css -o styles.css
cd ..
mkdir js && cd js
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjangoHerokuIn15/static/js/bootstrap.min.js -o bootstrap.min.js
cd ..
mkdir img && cd img
In this last folder, you will put all images you need.
URL SETTINGS AND VIEWS
In urls.py copy these lines right before ‘example’:
url(r'^$', "pmfmain.views.splash", name="splash"),
url(r'^login$', "pmfmain.views.login_view", name="login"),
url(r'^signup$', "pmfmain.views.register", name="signup"),
url(r'^forgot$', "pmfmain.views.forgot_pass", name="forgotmypass"),
url(r'^logout$', "pmfmain.views.logout_user", name="logout"),
url(r'^dashboard$', "pmfmain.views.home", name="home”),
then copy views.py from my github repo to your DJANGO_PROJECT folder:
cd ~/PROJECT_WRAPPER/DJANGO_APP/
rm views.py
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/views.py -o views.py
Do a find & replace replacing DjMainApp with your real DJANGO_APP name throughout the whole views.py
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/forms.py -o forms.py
GIT
Some files need not be in git, so let’s set the config for this:
echo -e "venv\n*.pyc\n*.log\n*.pot\nstaticfiles" > .gitignore
and now lets commit:
git init
git add .
git commit -m ‘initial commit of django app’
Create a repository in git, then copy the git url (the one that ends in .git). Then:
git remote add origin THE_URL
git pull origin master
BITBUCKET ALTERNATIVE
If you don’t want to pay for github and you want your repository private, you can use bitbucket.
Login to your account
Create a new repository
Click add existing project
git remote add origin https://USERNAME#bitbucket.org/USERNAME/REPOSITORY_NAME.git
MULTIPLE HEROKU ACCOUNTS & KEYS
Even if you never have to have multiple heroku accounts, it is an easy way to setup and use it even for one account. So on we go:
cd ~
heroku plugins:install git://github.com/ddollar/heroku-accounts.git
the add a heroku account with:
heroku accounts:add personal
Enter your Heroku credentials.
Email:YOUR_HEROKU_EMAIL
Password: YOUR_HEROKU_PASSWORD
It says it in the console, and you have to do it:
Add the following to your ~/.ssh/config
Host heroku.personal
HostName heroku.com
IdentityFile /PATH/TO/PRIVATE/KEY
IdentitiesOnly yes
Go to your project folder with something like:
cd ~/PROJECT_WRAPPER
and then set the new account as:
heroku accounts:set personal
To create a new ssh KEY:
ssh-keygen -t rsa
When asked for name, write the full path and name as shown. then type your password or leave blank
Then add the keys both to your OSX and heroku:
heroku keys:add ~/.ssh/YOUR_KEY_NAME.pub
ssh-add ~/.ssh/YOUR_KEY_NAME
DEPLOYING HEROKU FILES
Now that you have keys in order, you should be able to do
heroku apps
and see that there are no apps. To add your first app:
heroku apps:create YOUR_APP_NAME
And now to upload to the server:
git push heroku master
now go to YOUR_APP_NAME.herokuapp.com to see your site!
DOMAIN SETUP
remains to be explained if anybody wants, let me know
NOTES
In-depth documentation at:
https://docs.djangoproject.com/en/1.6/intro/tutorial01/
https://devcenter.heroku.com/articles/getting-started-with-django

In my other answer, the process is well described, but takes time. So I have made a ready installation that is good to go in less than 15minutes.
https://github.com/mgpepe/django-heroku-15
If you'd prefer the full explanation with the long path see the answer below.

THESE ARE THE ERRORS WHICH I FIND WHILE WORKING ON DJANGO FOR 2 YEARS [ENJOY]
Dyno should be added/seen in heroku->resources and if it is not added in resources of Heroku then it means there is a problem in the
"Procfile"
web: gunicorn [django_project].wsgi --log-file -
"django_project" above is your project name , change it to your project name
Remember to do changes in the settings.py file
DEBUG=True
ALLOWED_HOSTS = ["your-app.herokuapp.com","127.0.0.1"]
add this in settings.py file
#->this should be in the middleware
'whitenoise.middleware.WhiteNoiseMiddleware',
#->this at the bottom
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
[ First do "pip install django-heroku" ]
place this at the top of settings.py file:
import django_heroku
place this at the bottom of "settings.py" file:
django_heroku.settings(locals())
Heroku only works with postgres, remember this
[ go to https://www.elephantsql.com/ ]
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "",
"USER": "",
"PASSWORD": "",
"HOST": "",
"PORT": "5432",
}
}
Make Sure database in the background, if not running, start "postgres" in the services.msc.
[ This is in taskmanager->Services->postgresql->right click->start]
python manage.py migrate
go to "your app" in heroku and go to "settings" and select "Add buildpack" in the settings and select "python"
####################### Important ##############################
==> Create a new Git repository Initialize a git repository in a new or
existing directory
cd my-project/
git init
heroku git:remote -a iris-django-ml
==> Deploy your application
Commit your code to the repository and deploy it to Heroku using Git.
git add .
git commit -am "make it better"
git push heroku master
"run this command in your directory"
heroku login
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
restart again with deleting your git file of your working directory, delete heroku project (settings -> bottom)

Related

user table not created on django deployment but superuser created on heroku bash

I'm trying to upload my first django app and I've been struggle with this issue for sometime, help is appreciated.
I already set up my project to be on heroku, I followed this tutorial: https://www.youtube.com/watch?v=6DI_7Zja8Zc in which django_heroku module is used to configure DB, here is the link to library https://pypi.org/project/django-heroku/
The app throws the error on login as if user tables didn't exist but I already create a super user using the heroku bash feature, after apply migrations using "heroku run python manage.py migrate". When I run "ls" command on heroku bash this is my directory:
manage.py Procfile requirements.txt runtime.txt smoke staticfile
"smoke" is my folder app, should I could see the db in this directory? if the db was not created how could I create a superuser using heroku bash feature?
This is the DB configuration that django gives me on server:
{'default': {'ATOMIC_REQUESTS': False,
'AUTOCOMMIT': True,
'CONN_MAX_AGE': 0,
'ENGINE': 'django.db.backends.sqlite3',
'HOST': '',
'NAME': PosixPath('/app/db.sqlite3'),
'OPTIONS': {},
'PASSWORD': '********************',
'PORT': '',
'TEST': {'CHARSET': None,
'COLLATION': None,
'MIGRATE': True,
'MIRROR': None,
'NAME': None},
'TIME_ZONE': None,
'USER': ''}}
I see that db is sqlite3 and should be postgreSQL but I understand that django-heroku library should do that.
I don't know what other information could be useful because I have no experience deploying nothing so I will be pending on more information request to edit this question.
My gitignore file is this:
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
This is the bottom of my settings.py file:
...
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfile')
STATIC_URL = '/static/'
django_heroku.settings(locals())
Thank you.
If you look at the django-heroku repository on GitHub I think you'll find that it has been abandoned. It has a banner saying
This repository has been archived by the owner. It is now read-only.
and has not had a new commit on the master branch since October, 2018.
The heroku-on-django library aims to be an updated replacement for django-heroku:
This has been forked from django-heroku because it was abandoned and then renamed to django-on-heroku because old project has been archived.
It is also somewhat stagnant (the most recent commit to master at the time of writing is from October, 2020) but it should work better than django-heroku.
In either case, make sure to put this at the bottom of your settings.py as indicated in the documentation:
# Configure Django App for Heroku.
import django_on_heroku
django_on_heroku.settings(locals())

ValueError: Missing staticfiles manifest entry on Heroku with Docker, django-pipeline, whitenoise

I am trying to deploy a Django project on Heroku using Docker, django-pipeline, and whitenoise. The container builds successfully, and I see that collectstatic generates the expected files inside container-name/static. However, upon visiting any page I receive the following 500 error:
ValueError: Missing staticfiles manifest entry for 'pages/images/favicons/apple-touch-icon-57x57.png'
Below are my settings.py, Dockerfile, and heroku.yml. Since I'm also using django-pipeline, one thing I'm unsure of is what setting to use for STATICFILES_STORAGE? I tried
STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage'
but that lead to the file paths 404ing.
Any advice is appreciated. Thank you.
#settings.py
...
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env.bool("DJANGO_DEBUG", default=False)
ALLOWED_HOSTS = ['.herokuapp.com', 'localhost', '127.0.0.1']
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.admindocs",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.sites",
# Third-party
"allauth",
"allauth.account",
"debug_toolbar",
"django_extensions",
"pipeline",
"rest_framework",
"whitenoise.runserver_nostatic",
"widget_tweaks",
# Local
...
]
MIDDLEWARE = [
"debug_toolbar.middleware.DebugToolbarMiddleware",
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
...
]
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = "/static/"
# STATICFILES_DIRS = [str(BASE_DIR.joinpath("code/static"))]
STATIC_ROOT = str(BASE_DIR.joinpath("static"))
MEDIA_URL = "/media/"
MEDIA_ROOT = str(BASE_DIR.joinpath("media"))
# django-pipeline config
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
DEBUG_PROPAGATE_EXCEPTIONS = True
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
"pipeline.finders.PipelineFinder",
)
...
# Dockerfile
# Pull base image
FROM python:3.8
# Set environment variables and build arguments
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get install -y nodejs build-essential
# Set working directory
WORKDIR /code
COPY . /code/
RUN npm install sass --dev
RUN npm install yuglify --dev
RUN npm install
RUN mkdir static
RUN mkdir staticfiles
# Install dependencies
COPY Pipfile Pipfile.lock /code/
# Figure out conditional installation of dev dependencies
# Will need to remove --dev flag for production
RUN pip install pipenv && pipenv install --system --dev
# heroku.yml
setup:
addons:
- plan: heroku-postgresql
build:
docker:
web: Dockerfile
release:
image: web
command:
- python manage.py collectstatic --noinput
run:
web: gunicorn config.wsgi
UPDATE
Based on ENDEESA's response to this similar SO post, I updated my settings to the following, since my static files are stored inside pages/static/pages:
STATIC_URL = "/static/"
STATICFILES_DIRS = [str(BASE_DIR.joinpath("pages/static"))]
STATIC_ROOT = str(BASE_DIR.joinpath("static"))
I also noticed that my top-level urls.py file included the following line:
urlpatterns += staticfiles_urlpatterns()
As I understand it, this is useful for serving static files in development, but should not be used in production, so I moved it to only be added if DEBUG is True. But alas, the error persists.
More mysteriously, when I run
python manage.py findstatic <file-path> --verbosity 2
the file is found:
Found 'images/favicons/apple-touch-icon-57x57.png' here:
/code/pages/static/images/favicons/apple-touch-icon-57x57.png
/code/pages/static/images/favicons/apple-touch-icon-57x57.png
Looking in the following locations:
/code/pages/static
/code/static
/usr/local/lib/python3.8/site-packages/django/contrib/admin/static
/usr/local/lib/python3.8/site-packages/debug_toolbar/static
/usr/local/lib/python3.8/site-packages/django_extensions/static
/usr/local/lib/python3.8/site-packages/rest_framework/static
So why am I still getting ValueError: Missing staticfiles manifest entry?
SOLVED
At long last, I came to the following solution. My main issues were:
the static files appeared to be collected during the release command, but the actual STATIC_ROOT dir was empty in my container. I'm not sure why. My solution was to NOT run collectstatic as a release command in heroku.yml, and instead do so in Dockerfile.
NOTE: in order to collectstatic in my Dockerfile I needed to set a default for all environment variables, including SECRET_KEY, the latter for which I did using get_random_secret_key() from django.core.management.utils. Thank you to Ryan Knight for illustrating this here.
In addition to my settings.py needing a default secret key, my final static files settings were as shown below.
Since I'm using django-pipeline, my js files weren't loading correctly with whitenoise storage options. I wound up using pipeline.storage.PipelineStorage instead.
It turned out I did not need to set STATICFILES_DIRS at all. Previously I was setting it as:
STATICFILES_DIRS = [
str(BASE_DIR.joinpath("pages/static")),
str(BASE_DIR.joinpath("staticfiles")),]
Both were unnecessary because app_name/static/app_name is the default place Django will look for static files already, and I wasn't actually storing additional non-app-specific files in root/staticfiles. So I removed this setting.
In heroku.yml I removed the release command for collectstatic.
On the Settings page of my Heroku app's admin, I added a config variable for DISABLE_COLLECTSTATIC, set to 1.
# Dockerfile
# Pull base image
FROM python:3.8
# Set environment variables and build arguments
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get install -y nodejs build-essential
# Set working directory
WORKDIR /code
COPY . /code/
RUN npm install sass --dev
RUN npm install yuglify --dev
RUN npm install
# Install dependencies
COPY Pipfile Pipfile.lock /code/
RUN pip install pipenv && pipenv install --system
# Collect static files here instead of in heroku.yml so they end up in /code/static, as expected in the app
RUN python manage.py collectstatic --noinput
# settings.py
...
from django.core.management.utils import get_random_secret_key
SECRET_KEY = env("DJANGO_SECRET_KEY", default=get_random_secret_key())
...
STATIC_URL = "/static/"
STATIC_ROOT = str(BASE_DIR.joinpath("static"))
STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage'
DEBUG_PROPAGATE_EXCEPTIONS = True
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
"pipeline.finders.PipelineFinder",
)
...
# heroku.yml
setup:
addons:
- plan: heroku-postgresql
build:
docker:
web: Dockerfile
release:
image: web
run:
web: gunicorn config.wsgi
Project structure, in case it's helpful:
config
settings.py
...
pages
static
pages
scss
js
images
static
Dockerfile
heroku.yml
docker-compose.yml
...
Best of luck to anyone else battling the deployment gods. May the odds be ever in your favor, and don't give up!

Deploying an Angular 4 frontend with a Django Rest Framework backend on Heroku

I have built the front end using Angular 4 (using the angular CLI) and the backend using Django and the Django Rest Framework.
The development environment is set up in such a way that the static assets, HTML,JS etc are all part of the Angular app. The angular app runs on a server spun up by the CLI at localhost:4200 and and it communicates with the rest framework backend through a series of HTTP calls through CORS to the DRF API which is live at another localhost:8000 only to obtain and serve information.
How do I go about deploying this as a production-ready application on Heroku? The heroku guides illustrate how to deploy a Django app separately or an Angular app separately (running on a node server). Do i deploy them as two separate instances or do I combine them. If so , how do I go about doing that?
This solution doesn't match the request of how to do this on Heroku, but is done at request of #pdfarhad.
So first about what I used to host, my domain name was registered with Godaddy, and that pointed to a server (droplet) I created at Digitalocean. Noting that the DNS servers on godaddy were pointing to digitaloceans, ns1.digitalocean.com, ns2.digitalocean.com and ns3.digitalocean.com. Then on digitalocean, on the networking tab, created two A records that both point to the server I created, one being example.com, and the other being api.example.com.
With that done, when you create a new droplet, the password for the root user will be emailed, then do:
# ssh root#<IPADDRESSOFSERVER>
# sudo apt-get update
# sudo adduser jupiar
# sudo usermod -aG sudo jupiar
# su - jupiar
$ sudo apt-get install nginx
At this point, you should be able to navigate to your IPADDRESS and see the nginx landing page, you might have to wait a while for godaddy and digitalocean to pass typing example.com, I think half a day passed until the name servers were all synced up and stuff.
Now, I just set up passwordless ssh, on my local machine:
$ ssh-keygen (no passphrase)
$ cat ~/.ssh/id_rsa.pub (then copy this)
And now on the server:
$ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ nano ~/.ssh/authorized_keys (paste the rsa you copied)
$ chmod 600 ~/.ssh/authorized_keys
$ sudo nano /etc/ssh/sshd_config
| Make sure:
| PasswordAuthentication no
| PubkeyAuthentication yes
| ChallengeResponseAuthentication no
$ sudo systemctl reload sshd
$ exit
Now you should be able to ssh into your server without a password.
I use anaconda python because I do alot of datascience, so:
$ wget https://repo.continuum.io/archive/Anaconda3-5.0.0.1-Linux-x86_64.sh
$ bash https://repo.continuum.io/archive/Anaconda3-5.0.0.1-Linux-x86_64.sh
| installed to /home/jupiar/anaconda3, auto append path to .bashrc
$ . .bashrc
$ source .bashrc
Now, because in the past I had some trouble with running linux supervisor with python virtualenvs, I just install everything globally. uwsgi is mostly in C, so you need some packages so as to compile it.
$ sudo apt-get install build-essential python-dev python3-dev
$ pip install uwsgi
Now, making a git repository, you can make one on the server, but i prefer to use github, because it provides alot of useful tools, and a good place to collaborate between contributers on the project, so make a private repository on github, then on your local machine: (the third line is because I use Mac)
MAKE A NEW FOLDER, and put everything in there
$ echo "# example" >> README
$ git init
$ find . -name .DS_Store -print0 | xargs -0 git rm -f --ignore-unmatch
$ echo ".DS_Store" >> .gitignore
$ git add .
$ git commmit -m "first commit"
$ git remote add origin https://github.com/<GITUSERNAME>/<REPONAME>.git
$ git push -u origin master
so, again on the local machine, set up a new angular 4 app with scss styling and skipping making it a git repo, because it wont show properly on github, repo inside repo etc... :
$ ng new frontend --style=scss --skip-git
And, we will keep the app as it is for now, just remember the server will need a dist folder, and you can do something like this in the frontend folder, using ahead-of-time...:
$ ng build --aot -prod
Now on local machine again, create the Django Rest Framework backend:
$ conda create -n exampleenv python=3.6 anaconda
$ source activate exampleenv
(exampleenv)$ pip install django
(exampleenv)$ pip install djangorestframework
(exampleenv)$ pip install django-cors-headers
(exampleenv)$ django-admin startproject backend
(exampleenv)$ cd backend
(exampleenv)$ django-admin startapp api
(exampleenv)$ python manage.py migrate
(exampleenv)$ python manage.py createsuperuser
Now, just to get a minimal rest framework to work, we need to:
In settings.py add to INSTALLED APPS:
'rest_framework',
'corsheaders',
'api',
In settings.py add to top of MIDDLEWARE:
'corsheaders.middleware.CorsMiddleware',
In settings.py add:
CORS_ORIGIN_ALLOW_ALL = True
In settings.py add:
ALLOWED_HOSTS = ['<DIGITALOCEANSERVER-IP>', '*', 'localhost', '127.0.0.1']
in backend/urls.py:
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include('api.urls')),
]
in api/models.py:
from django.db import models
# Create your models here.
class testModel(models.Model):
word = models.CharField("word", max_length=20)
in api/serializers.py:
from rest_framework import serializers
from .models import testModel
class testSerializer(serializers.ModelSerializer):
word = serializers.CharField(max_length=20)
class Meta:
model = testModel
fields = ('id', 'word')
in api/urls.py:
from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from .views import testView
urlpatterns = [
url(r'^test/', testView.as_view()),
]
in api/views.py:
from rest_framework import generics
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from django.shortcuts import render
from .models import testModel
from.serializers import testSerializer
# Create your views here.
class testView(APIView):
def get(self, request):
return Response({'succeded?', 'yes'})
Now with all that saved, it should work if you:
(exampleenv)$ python manage.py runserver
navigate to :8000/api/test/
With both an angular 4 frontend and DRF backend done, we can push the changes to github, by now that will be a LOT of changes ;)
Now, lets get our frontend and backend onto the server, log into the server and good idea now is to add the ssh keys from your server (and local machine) if you havnt already, to github. On the server we can do this via:
$ ssh-keygen -t rsa -b 4096 -C "<EMAIL ADDRESS>"
$ eval "$(ssh-agent -s)"
Agent pid ....
$ ssh-add ~/.ssh/id_rsa
Enter passphrase for /home/jupair/.ssh/id_rsa:
Identity added: /home/jupiar/.ssh/id_rsa (/home/jupiar/.ssh/id_rsa)
$ mkdir example
$ cd example
$ git init
$ git pull git#github.com:<GITHUBUSERNAME>/<REPONAME>.git
(At some point here, you might have errors with using https or ssh) if you are using ssh keys, you need to use the ssh repo name from github (on github, the clone or download button will give you these links), and on the local machine too you may need to set-url to use the ssh name):
[on local machine]
$ git remote set-url origin git#github.com:<GITHUBUSERNAME>/<REPONAME>.git
Okay, now on your server, you should have the frontend and backend folders in your project folder, angular is very easy, on the server:
$ cd /etc/nginx/sites-available
$ sudo rm default
$ sudo nano frontend.conf
and place something like this inside:
server {
listen 80;
listen [::]:80;
root /home/jupiar/example/frontend/dist;
index index.html index.htm index.nginx-debian.html;
server_name example.com;
location / {
try_files $uri $uri/ =404;
}
}
Now we need to link that file into sites enabled:
$ sudo ln -s /etc/nginx/sites-available/frontend.conf /etc/nginx/sites-enabled/frontend.conf
$ cd /etc/nginx/sites-enabled
$ sudo rm default
$ sudo systemctl restart nginx.service
Heading over to example.com we should now see the angular app working,
Okay, now to make the backend servable, is a little bit more tricky:
$ cd /etc/nginx/sites-available
$ sudo nano backend.conf
and place something like this:
server {
listen 80;
listen [::]:80;
server_name api.example.com;
location /static/admin {
alias /home/jupair/anaconda3/lib/python3.6/site-packages/django/contrib/admin/static/admin;
}
location /static/rest_framework {
alias /home/jupiar/anaconda3/lib/python3.6/site-packages/rest_framework/static/rest_framework;
}
location / {
proxy_pass http://127.0.0.1:9000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
Now, link that file to sites-enabled:
$ sudo ln -s /etc/nginx/sites-available/backend.conf /etc/nginx/sites-enabled/backend.conf
Now to set up superviser to use uwsgi to start the django app
$ sudo apt-get install supervisor
$ sudo nano /etc/supervisor/conf.d/backend_api.conf
And inside, have something like:
[program:backend_api]
command = /home/jupiar/anaconda3/bin/uwsgi --http :9000 --wsgi-file /home/jupiar/example/backend/backend/wsgi.py
directory = /home/jupiar/example/backend
user = jupiar
autostart = true
autorestart = true
stdout_logfile = /var/log/backnd_api.log
stderr_logfile = /var/log/backend_api_err.log
Now, you will need to run:
$ sudo supervisorctl reread
$ sudo supervisorctl update
$ sudo supervisorctl restart backend_api
$ sudo systemctl restart nginx.service
Now, heading over to api.example.com/api/test/ should give you the django rest framework response of suceeded: true.
From now on, you can just use a custom shell script whenever you want to make changes live, that would be like:
cd /home/jupiar/example
git reset --hard (sometimes you may need to run this)
git pull git#github.com/<GITUSERNAME>/<PROJECTNAME>.git
sudo supervisorctl restart backend_api
sudo systemctl restart nginx.service
And thats pretty much it, I believe everything is there from how I remember doing it, any questions or if something is wrong/doesn't work for you, please comment and let me know :)

how process static file when deploying django using docker and aws eb

I used Django, Docker and AWS Elastic Beanstalk to employ my website. I followed the instruction of https://github.com/glynjackson/django-docker-template.
I met problem when I try to load static file, the browser try to visit mysite.com/static/css/xx.css to get the css and javascipt file which is different with what I run it locally.
In settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = 'static'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
I also used:
# !/bin/sh
cd /var/projects/mysite && python manage.py migrate --noinput && python manage.py collectstatic --noinput
supervisord -n -c /etc/supervisor/supervisord.conf
Currently, I write additional views and urls for javascript and css file. So browser can get these file from url. But how to do it correctly?

Problems deploying GeoDjango application on Heroku

I'm having troubles to deploy my GeoDjango application on heroku (using Free Dyno but I'm able to change if necessary). When I execute push heroku master --force I got the following error:
Try using 'django.db.backends.XXX', where XXX is one of:
'mysql', 'oracle', 'postgresql', 'sqlite3'
Error was: cannot import name 'GDALRaster'
I already installed postgis:
$ heroku pg:psql
create extension postgis;
Configured buildpacks:
heroku config:add BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git
Created .buildpacks file at my project with this links:
https://github.com/cyberdelia/heroku-geo-buildpack.git#1.1
https://github.com/heroku/heroku-buildpack-python.git#v29
Updated Procfile:
web: python manage.py collectstatic --noinput; gunicorn projectname.wsgi
My settings.py it's configured:
INSTALLED_APPS = [
....
'django.contrib.gis',
]
default_dburl = 'sqlite:///' + os.path.join(BASE_DIR, 'db.sqlite3')
DATABASES = {
'default': config('DATABASE_URL', default=default_dburl, cast=dburl),
}
DATABASES['default']['ENGINE'] = config('DB_ENGINE')
My DB_ENGINE is at .env file:
DB_ENGINE=django.contrib.gis.db.backends.postgis
References I already read:
Installing postgis
Buildpacks
Buildpacks 2
Configuring GeoDjango
I can't figure out solutions,
Thanks in advance for any help.
You need to install GDAL in your heroku instance.
Here is the buildpack for heroku
https://github.com/mojodna/heroku-buildpack-gdal
A friend helped me in other forum, he told me to change the buildpack url on heroku to:
git://github.com/dulaccc/heroku-buildpack-geodjango.git#1.1
And I added this lines to settings.py:
GEOS_LIBRARY_PATH = environ.get('GEOS_LIBRARY_PATH')
GDAL_LIBRARY_PATH = environ.get('GDAL_LIBRARY_PATH')
It solved the problem to deploy the application.
Thanks.