My Django project uses Docker, gunicorn, and whitenoise. I recently altered settings to prepare for deployment, most notably adding configurations for AWS-hosted media files. Now when I run the project locally and collectstatic the static files do not update in the browser. I do, however, see the changes where static files are collected.
Things I've tried/double checked:
Ensuring I have a shared volume between the container and where static files are kept/updated
Adding a step to collectstatic in my Dockerfile
Confirming my static files settings
Is something about django-storages causing the issue? I thought that previously I was able to make SCSS changes and have them show up by refreshing the browser. But that's not happening. Even running collectstatic inside the container has no effect.
# relevant settings.py
INSTALLED_APPS = [
...
"whitenoise.runserver_nostatic",
"storages",
...
]
MIDDLEWARE = [
"django.middleware.cache.UpdateCacheMiddleware",
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
...
]
# AWS config (use in production only)
USE_S3 = env.bool("USE_S3", default=not DEBUG)
if USE_S3:
AWS_ACCESS_KEY_ID = env.str("AWS_ACCESS_KEY_ID", default="")
AWS_SECRET_ACCESS_KEY = env.str("AWS_SECRET_ACCESS_KEY", default="")
AWS_STORAGE_BUCKET_NAME = env.str("AWS_STORAGE_BUCKET_NAME", default="")
AWS_DEFAULT_ACL = None
AWS_S3_REGION_NAME = env.str("AWS_S3_REGION_NAME", default="us-east-2")
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
# S3 Public Media Settings
PUBLIC_MEDIA_LOCATION = 'media'
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_MEDIA_LOCATION}/'
# S3 Private Media Settings
DEFAULT_FILE_STORAGE = 'config.storage_backends.PrivateMediaStorage'
PRIVATE_MEDIA_LOCATION = 'private'
PRIVATE_FILE_STORAGE = 'config.storage_backends.PrivateMediaStorage'
else:
MEDIA_URL = "/media/"
MEDIA_ROOT = str(BASE_DIR.joinpath("media"))
STATIC_ROOT = str(BASE_DIR.joinpath("staticfiles"))
STATIC_URL = '/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",
)
PIPELINE_YUGLIFY_BINARY = "/usr/local/bin/node"
PIPELINE = {
"CSS_COMPRESSOR": "pipeline.compressors.yuglify.YuglifyCompressor",
"COMPILERS": (
"pipeline.compilers.sass.SASSCompiler",
"config.compilers.RollupCompiler",
),
"YUGLIFY_BINARY": str(BASE_DIR.joinpath("node_modules/.bin", "yuglify")),
"SASS_BINARY": str(BASE_DIR.joinpath("node_modules/.bin", "sass")),
"STYLESHEETS": {
"twirlmate": {
"source_filenames": ("pages/scss/styles.scss",),
"output_filename": "css/styles.css",
}
},
"JS_COMPRESSOR": "pipeline.compressors.NoopCompressor", # TODO: Update this to jsmin or something better.
"ROLLUP_BINARY": str(BASE_DIR.joinpath("node_modules/.bin", "rollup")),
"ROLLUP_ARGUMENTS": ["--config", "--configDebug", "--format", "iife"],
"DISABLE_WRAPPER": True,
"JAVASCRIPT": {
"twirlmate": {
"source_filenames": (
"pages/js/core.js",
"pages/js/file-field.js",
"pages/js/lazy-loading.js",
"pages/js/modal.js",
"pages/js/navigation.js",
"pages/js/notifications.js",
),
"output_filename": "js/twirlmate.js",
},
"components": {
"source_filenames": ("pages/js/vue/components.rollup.js",),
"output_filename": "js/components.js",
},
},
}
#docker-compose.yml
version: '3.8'
services:
web:
build: .
command: gunicorn config.wsgi -b 0.0.0.0:8000
volumes:
- .:/code
ports:
- 8000:8000
depends_on:
- db
environment:
- "DJANGO_SECRET_KEY=****"
- "DJANGO_DEBUG=True"
- "DJANGO_SECURE_SSL_REDIRECT=False"
- "SECURE_HSTS_SECONDS=0"
- "SECURE_HSTS_INCLUDE_SUBDOMAINS=False"
- "SECURE_HSTS_PRELOAD=False"
- "SESSION_COOKIE_SECURE=False"
- "CSRF_COOKIE_SECURE=False"
db:
image: postgres:11
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- "POSTGRES_HOST_AUTH_METHOD=trust"
volumes:
postgres_data:
# 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
RUN npm install sass --also=dev
RUN npm install yuglify --also=dev
RUN npm install
# 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
COPY . /code/
# Collect static files
RUN python manage.py collectstatic --noinput
Project Structure
twirlmate
├── .babelrc
├── .env
├── .gitignore
├── .pylintrc
├── Dockerfile
├── Makefile
├── Pipfile
├── Pipfile.lock
├── config
│ ├── __init__.py
│ ├── asgi.py
│ ├── compilers.py
│ ├── compressors.py
│ ├── constants.py
│ ├── settings.py
│ ├── storage_backends.py
│ ├── urls.py
│ └── wsgi.py
├── docker-compose.yml
├── heroku.yml
├── manage.py
├── package-lock.json
├── package.json
├── pages
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── static
│ │ └── pages
│ │ ├── css
│ │ │ ├── styles.css
│ │ │ └── styles.css.map
│ │ ├── fonts
│ │ ├── images
│ │ ├── js
│ │ │ └── vue
│ │ │ ├── components
│ │ │ │ ├── cards
│ │ │ │ ├── inputs
│ │ │ │ ├── miniMenus
│ │ │ │ └── modals
│ │ │ ├── components.rollup.js
│ │ │ ├── data
│ │ │ ├── directives
│ │ │ ├── forms
│ │ │ ├── mixins
│ │ │ ├── services
│ │ │ ├── views
│ │ │ └── vue-store.js
│ │ └── scss
│ │ ├── 01-utilities
│ │ ├── 02-vendors
│ │ ├── 03-base
│ │ ├── 04-layout
│ │ ├── 05-components
│ │ ├── 06-pages
│ │ ├── styles.css
│ │ ├── styles.css.map
│ │ └── styles.scss
│ ├── templatetags
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ ├── css_classes.py
│ │ └── url_paths.py
│ ├── tests
│ │ ├── __init__.py
│ │ └── test_views.py
│ ├── urls.py
│ └── views.py
├── pyproject.toml
├── rollup.config.js
├── staticfiles
│ ├── admin
│ ├── debug_toolbar
│ ├── django_extensions
│ ├── pages
│ │ ├── css
│ │ │ ├── styles.css
│ │ │ └── styles.css.map
│ │ ├── fonts
│ │ ├── images
│ │ ├── js
│ │ │ └── vue
│ │ │ ├── components
│ │ │ │ ├── cards
│ │ │ │ ├── inputs
│ │ │ │ ├── miniMenus
│ │ │ │ └── modals
│ │ │ ├── components.rollup.js
│ │ │ ├── components.rollup.roll.js
│ │ │ ├── data
│ │ │ ├── directives
│ │ │ ├── forms
│ │ │ ├── mixins
│ │ │ ├── views
│ │ │ └── vue-store.js
│ │ └── scss
│ │ ├── 01-utilities
│ │ ├── 02-vendors
│ │ ├── 03-base
│ │ ├── 04-layout
│ │ ├── 05-components
│ │ ├── 06-pages
│ │ ├── styles.css
│ │ ├── styles.css.map
│ │ └── styles.scss
│ └── rest_framework
└── templates
├── 403.html
├── _base.html
├── account
│ ├── login.html
│ ├── password_change.html
│ ├── password_change_done.html
│ ├── password_reset.html
│ ├── password_reset_done.html
│ ├── password_reset_from_key.html
│ ├── password_reset_from_key_done.html
│ └── signup.html
├── emails
│ ├── duet_invitation.html
│ └── duet_invitation.txt
├── includes
│ ├── _favicons.html
│ ├── _footer.html
│ ├── _header.html
│ └── forms
│ ├── _widgets.html
│ └── attrs.html
├── index.html
├── pages
│ ├── for_coaches.html
│ ├── for_directors.html
│ └── home.html
├── registration
│ ├── account-settings.password-change-done.html
│ ├── account-settings.password-change.html
│ ├── account-settings.profile-list.html
│ └── privacy-policy.html
└── studios
├── _studio_admin_base.html
├── my_studios.html
├── staff_list.html
├── studio_create.html
├── studio_detail.admin.html
├── studio_detail.html
├── studio_join.html
├── studio_list.html
├── studio_update.html
└── team_list.html
index.html, from which all other templates inherit
{% load static pipeline %}
<!doctype html>
<html class="no-js" lang="en">
<head>
... other various meta tags ...
{% stylesheet 'twirlmate' %}
<!-- the above produces the path: /static/pages/scss/styles.css -->
{% block styles %}{% endblock %}
{% block extrastyles %}{% endblock %}
</head>
<body class="{% block body-class %}{% endblock %}" {% block body-attributes %}{% endblock %}>
<div class="main-wrapper" data-target="main-wrapper">
<a class="skip-to-main" href="#main">Skip to main content</a>
{% block header %}{% endblock header %}
{% block notifications %}{% endblock notifications %}
{% block main %}{% endblock main %}
{% block footer %}{% endblock footer %}
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
{% javascript 'twirlmate' %}
{% javascript 'components' %}
{% block scripts %}{% endblock scripts %}
{% block extrascripts %}{% endblock extrascripts %}
</body>
</html>
SOLVED
It turns out there was a duplicate, stale file with the same name, and the same path. The template was looking for /static/pages/scss/styles.css, which existed in its updated form in my root static directory, the correct spot. But there was also a file in pages/static/pages/scss/styles.css that must've gotten generated during previous changes to settings.py. Somehow I guess that file was getting repeatedly pulled in and overwriting the updated version. All was fixed once I deleted the stale file.
Related
I've been digging through articles and posts about this subject but can't seem to get my images to load. For some reason the CSS on my pages seems to load just fine.
settings.py
BASE_DIR = Path(__file__).resolve().parent.parent
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
also I tried
STATIC_ROOT = '/var/www/myname/'
template
<img src="{% static 'picture.jpg' %}" class="img-fluid">
NGINX
/etc/nginx/sites-enabled/django_project
server {
listen 80;
server_name mywebsite.com;
location /static/ {
alias /var/www/myname/static/;
}
}
directories
/var/www/myname
└── static
└── admin
├── css
│ ├── styles1.css
│ └── styles2.css
├── images
│ ├── picture.jpg
│ └── python.jpg
└── js
└── scripts.js
/home/myname/myprojectdir
├── django_project
│ ├── django_project
│ │ └── __pycache__
│ ├── etc
│ ├── index
│ │ ├── migrations
│ │ │ └── __pycache__
│ │ ├── __pycache__
│ │ └── templates
│ │ └── index
│ │ └── backups
│ ├── __pycache__
│ └── static
│ ├── admin
│ │ ├── css
│ │ │ └── vendor
│ │ │ └── select2
│ │ ├── fonts
│ │ ├── images
│ │ │ └── gis
│ │ ├── img
│ │ │ └── gis
│ │ └── js
│ │ ├── admin
│ │ └── vendor
│ │ ├── jquery
│ │ ├── select2
│ │ │ └── i18n
│ │ └── xregexp
│ ├── images
│ └── index
│ ├── css
│ ├── images
│ └── js
├── myname_env
│ ├── bin
│ └── lib
│ └── python3.10
│ └── site-packages
└── static
└── admin
├── css
│ └── vendor
│ └── select2
├── fonts
├── img
│ └── gis
└── js
├── admin
└── vendor
├── jquery
├── select2
│ └── i18n
└── xregexp
I've tried installing the static files in other directories, etc, to see what works but I'm not having any luck whatsoever. I had the static files in the project but after reading that's not a good practice I put them into var/www.
can you add this into nginx conf and try:
location /images/ {
alias /var/www/myname/static/images;
}
My project folder looks this:
├── Procfile
├── core
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-39.pyc
│ │ └── views.cpython-39.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── db.sqlite3
├── inspirationSources.txt
├── manage.py
├── package-lock.json
├── package.json
├── react-frontend
│ ├── README.md
│ ├── build
│ │ ├── asset-manifest.json
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ ├── robots.txt
│ │ └── static
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── assets
│ ├── components
│ ├── hooks
│ ├── index.css
│ └── index.js
├── requirements.txt
├── spotify
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-39.pyc
│ │ ├── admin.cpython-39.pyc
│ │ ├── apps.cpython-39.pyc
│ │ ├── cluster.cpython-39.pyc
│ │ ├── credentials.cpython-39.pyc
│ │ ├── models.cpython-39.pyc
│ │ ├── urls.cpython-39.pyc
│ │ ├── util.cpython-39.pyc
│ │ └── views.cpython-39.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── cluster.py
│ ├── credentials.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ ├── models.py
│ ├── templates
│ ├── tests.py
│ ├── urls.py
│ ├── util.py
│ └── views.py
├── spotifycluster
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-39.pyc
│ │ ├── settings.cpython-39.pyc
│ │ ├── urls.cpython-39.pyc
│ │ └── wsgi.cpython-39.pyc
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── tutorialSources.txt
When I deploy with git push heroku main it seems to be fine but when I open the app in browser using the complementary url, I get the following errors on screen (debug mode is on):
TemplateDoesNotExist at /
build/index.html
Request Method: GET
Request URL: https://nameless-taiga-02413.herokuapp.com/
Django Version: 3.1.7
Exception Type: TemplateDoesNotExist
Exception Value:
build/index.html
Exception Location: /app/.heroku/python/lib/python3.9/site-packages/django/template/loader.py, line 19, in get_template
Python Executable: /app/.heroku/python/bin/python
Python Version: 3.9.4
Python Path:
['/app/.heroku/python/bin',
'/app',
'/app/.heroku/python/lib/python39.zip',
'/app/.heroku/python/lib/python3.9',
'/app/.heroku/python/lib/python3.9/lib-dynload',
'/app/.heroku/python/lib/python3.9/site-packages']
Server time: Fri, 30 Apr 2021 10:08:26 +0000
Template-loader postmortem
Django tried loading these templates, in this order:
Using engine django:
django.template.loaders.filesystem.Loader: /app/react-frontend/build/index.html (Source does not exist)
django.template.loaders.app_directories.Loader: /app/.heroku/python/lib/python3.9/site-packages/django/contrib/admin/templates/build/index.html (Source does not exist)
django.template.loaders.app_directories.Loader: /app/.heroku/python/lib/python3.9/site-packages/django/contrib/auth/templates/build/index.html (Source does not exist)
I have the following settings in my settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
Also I have whitenoise in my middleware list
MIDDLEWARE = [
'whitenoise.middleware.WhiteNoiseMiddleware',
...]
The templates section in settings.py looks as follows
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'react-frontend')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
I expected that Heroku would be able to find the static folder based on the STATIC_DIRS variable but that doesn't seem to be the case. Any clue what's going on here?
So actually it was a really stupid mistake. react-frontend was a broken submodule and I needed to fix that by making sure .git/config didn't have submodules and removing react-frontend from the cache (No submodule mapping found in .gitmodules for path and missing .gitmodules file). Commit and pushed again and it worked...
if your DEBUG is set to False Django din't handle STATIC FILES. Heroku provide some configuration to serve STATIC FILES
STEP-1 : install whitenoise
$ pip install whitenoise
STEP-2 : check in settings.py whitenoise middleware by default it available in MIDDLEWARE if it's not that add it.
MIDDLEWARE = (
'whitenoise.middleware.WhiteNoiseMiddleware',
...)
STEP-3: add this in your settings.py
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
I know this has been asked a lot of times but none of the solutions seem to work. I am trying to run a Django app in Heroku but am running into issues when I try to scale dynos.
➜ main-website git:(master) heroku ps:scale web=1
Scaling dynos... !
▸ Couldn't find that process type (web).
The issue seems to be related to ProcFile. This is what I have configured in my root directory (same as requirements.txt etc).
web: gunicorn main-website.wsgi:application --log-file -
What am I missing or doing wrong so I can correct this?
Project Structure
➜ main-website git:(master) tree -L 3
.
├── app
│ ├── about
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── __init__.py
│ │ ├── migrations
│ │ ├── models.py
│ │ ├── __pycache__
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── app
│ │ ├── asgi.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── contact
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── __init__.py
│ │ ├── migrations
│ │ ├── models.py
│ │ ├── __pycache__
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── core
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── __init__.py
│ │ ├── migrations
│ │ ├── models.py
│ │ ├── __pycache__
│ │ ├── tests
│ │ ├── tests.py
│ │ └── views.py
│ ├── db.sqlite3
│ ├── home
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── __init__.py
│ │ ├── migrations
│ │ ├── models.py
│ │ ├── __pycache__
│ │ ├── static
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── manage.py
│ ├── privacy
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── __init__.py
│ │ ├── migrations
│ │ ├── models.py
│ │ ├── __pycache__
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── static
│ │ ├── app
│ │ ├── css
│ │ ├── images
│ │ └── scripts
│ └── templates
│ ├── about.html
│ ├── contact.html
│ ├── footer.html
│ ├── header.html
│ ├── home.html
│ ├── layout.html
│ ├── privacy.html
│ └── slider.html
├── docker-compose.yml
├── Dockerfile
├── LICENSE
├── ProcFile
└── requirements.txt
The file name is Procfile not ProcFile.
Then try this web: gunicorn main-website.wsgi:application --log-file -
I developed locally using Docker and cookiecutter-django.
Cookiecutter-django creates several Dockerfiles within the "compose" directory.
I am now trying to push the project to Heroku.
However, heroku container:push web will return No images to push.
If I try the same command within a subdirectory of the compose directory, it will eventually break--probably due to an attempt at only pushing partial dockerfiles.
How do I get this up and running on Heroku taking advantage of Heroku containers?
This article from Heroku says I can push multiple images using by renaming the Dockerfiles, but I'm not sure how to figure out which of these cookiecutter-generated Dockerfiles are of which process type.
docker images will return:
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 16e570f295a7 10 minutes ago 318MB
luup_celeryworker latest bd7ff7e5eb10 2 hours ago 531MB
luup_django latest bd7ff7e5eb10 2 hours ago 531MB
luup_celerybeat latest bd7ff7e5eb10 2 hours ago 531MB
luup_postgres latest e50eb7b8a704 2 hours ago 287MB
registry.heroku.com/fierce-forest-57627/web latest 27690b3e49d4 16 hours ago 766MB
python 3.6-alpine c3a4a35c9244 22 hours ago 90MB
This is the Dockerfile made by cookiecutter. It is the DF under compose/production/django. There are other DFs--for caddy, postgres, as well as DFs for local.
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
RUN apk update \
# psycopg2 dependencies
&& apk add --virtual build-deps gcc python3-dev musl-dev \
&& apk add postgresql-dev \
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
# CFFI dependencies
&& apk add libffi-dev openssl-dev py-cffi
RUN addgroup -S django \
&& adduser -S -G django django
# Requirements have to be pulled and installed here, otherwise caching won't work
COPY ./requirements /requirements
RUN pip install --no-cache-dir -r /requirements/production.txt \
&& rm -rf /requirements
COPY ./compose/production/django/gunicorn.sh /gunicorn.sh
RUN sed -i 's/\r//' /gunicorn.sh
RUN chmod +x /gunicorn.sh
RUN chown django /gunicorn.sh
COPY ./compose/production/django/entrypoint.sh /entrypoint.sh
RUN sed -i 's/\r//' /entrypoint.sh
RUN chmod +x /entrypoint.sh
RUN chown django /entrypoint.sh
COPY ./compose/production/django/celery/worker/start.sh /start-celeryworker.sh
RUN sed -i 's/\r//' /start-celeryworker.sh
RUN chmod +x /start-celeryworker.sh
COPY ./compose/production/django/celery/beat/start.sh /start-celerybeat.sh
RUN sed -i 's/\r//' /start-celerybeat.sh
RUN chmod +x /start-celerybeat.sh
COPY . /app
RUN chown -R django /app
USER django
WORKDIR /app
ENTRYPOINT ["/entrypoint.sh"]
Please let me know if you need any more information
Edit--adding tree:
note: I've renamed the Dockerfiles to Dockerfile.processtype as instructed by Heroku here--Although I'm no longer pushing multiple images.. As you can tell in the tree, I've also moved a copy of Dockerfile.django and Dockerfile.local to the root of the project, as that's where it needs to be in order to Heroku container:push processtype --recursive.
├── Dockerfile.django
├── Dockerfile.local
├── LICENSE
├── Procfile
├── README.rst
├── compose
│ ├── local
│ │ └── django
│ │ ├── celery
│ │ │ ├── beat
│ │ │ │ └── start.sh
│ │ │ └── worker
│ │ │ └── start.sh
│ │ └── start.sh
│ └── production
│ ├── caddy
│ │ ├── Caddyfile
│ │ └── Dockerfile.caddy
│ ├── django
│ │ ├── Dockerfile.django
│ │ ├── celery
│ │ │ ├── beat
│ │ │ │ └── start.sh
│ │ │ └── worker
│ │ │ └── start.sh
│ │ ├── entrypoint.sh
│ │ └── gunicorn.sh
│ └── postgres
│ ├── Dockerfile.postgres
│ └── maintenance
│ ├── _sourced
│ │ ├── constants.sh
│ │ ├── countdown.sh
│ │ ├── messages.sh
│ │ └── yes_no.sh
│ ├── backup
│ ├── backups
│ └── restore
├── config
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-35.pyc
│ │ ├── __init__.cpython-36.pyc
│ │ ├── urls.cpython-36.pyc
│ │ └── wsgi.cpython-36.pyc
│ ├── settings
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── __init__.cpython-35.pyc
│ │ │ ├── __init__.cpython-36.pyc
│ │ │ ├── base.cpython-35.pyc
│ │ │ ├── base.cpython-36.pyc
│ │ │ ├── local.cpython-35.pyc
│ │ │ ├── local.cpython-36.pyc
│ │ │ └── production.cpython-36.pyc
│ │ ├── base.py
│ │ ├── local.py
│ │ ├── production.py
│ │ └── test.py
│ ├── urls.py
│ └── wsgi.py
├── docs
│ ├── Makefile
│ ├── __init__.py
│ ├── conf.py
│ ├── deploy.rst
│ ├── docker_ec2.rst
│ ├── index.rst
│ ├── install.rst
│ └── make.bat
├── heroku.yml
├── local.yml
├── locale
│ └── README.rst
├── lurnup
│ ├── __init__.py
│ ├── __pycache__
│ │ └── __init__.cpython-36.pyc
│ ├── contrib
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ └── __init__.cpython-36.pyc
│ │ └── sites
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ └── __init__.cpython-36.pyc
│ │ └── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_alter_domain_unique.py
│ │ ├── 0003_set_site_domain_and_name.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ ├── 0001_initial.cpython-36.pyc
│ │ ├── 0002_alter_domain_unique.cpython-36.pyc
│ │ ├── 0003_set_site_domain_and_name.cpython-36.pyc
│ │ └── __init__.cpython-36.pyc
│ ├── static
│ │ ├── css
│ │ │ └── project.css
│ │ ├── fonts
│ │ ├── images
│ │ │ └── favicon.ico
│ │ ├── js
│ │ │ └── project.js
│ │ └── sass
│ │ ├── custom_bootstrap_vars.scss
│ │ └── project.scss
│ ├── taskapp
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── __init__.cpython-36.pyc
│ │ │ └── celery.cpython-36.pyc
│ │ └── celery.py
│ ├── templates
│ │ ├── 403_csrf.html
│ │ ├── 404.html
│ │ ├── 500.html
│ │ ├── account
│ │ │ ├── account_inactive.html
│ │ │ ├── base.html
│ │ │ ├── email.html
│ │ │ ├── email_confirm.html
│ │ │ ├── login.html
│ │ │ ├── logout.html
│ │ │ ├── password_change.html
│ │ │ ├── password_reset.html
│ │ │ ├── password_reset_done.html
│ │ │ ├── password_reset_from_key.html
│ │ │ ├── password_reset_from_key_done.html
│ │ │ ├── password_set.html
│ │ │ ├── signup.html
│ │ │ ├── signup_closed.html
│ │ │ ├── verification_sent.html
│ │ │ └── verified_email_required.html
│ │ ├── base.html
│ │ ├── pages
│ │ │ ├── about.html
│ │ │ └── home.html
│ │ └── users
│ │ ├── user_detail.html
│ │ ├── user_form.html
│ │ └── user_list.html
│ └── users
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ ├── adapters.cpython-36.pyc
│ │ ├── admin.cpython-36.pyc
│ │ ├── apps.cpython-36.pyc
│ │ ├── models.cpython-36.pyc
│ │ ├── urls.cpython-36.pyc
│ │ └── views.cpython-36.pyc
│ ├── adapters.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ ├── 0001_initial.cpython-36.pyc
│ │ └── __init__.cpython-36.pyc
│ ├── models.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── factories.py
│ │ ├── test_admin.py
│ │ ├── test_models.py
│ │ ├── test_urls.py
│ │ └── test_views.py
│ ├── urls.py
│ └── views.py
├── manage.py
├── merge_production_dotenvs_in_dotenv.py
├── production.yml
├── pytest.ini
├── requirements
│ ├── base.txt
│ ├── local.txt
│ └── production.txt
Cookiecutter-django provides a standard docker compose configuration that you can push on several hosting services with full Docker support.
However, Heroku supports Docker with a few restrictions. For instance, the port for the WSGI server is hardcoded to 5000, where Heroku requires to use the environment variable $PORT.
These are NOT accounted for in cookiecutter-django, so you will have to change a few things:
I'd start with the images in compose/production/django and ignore the DB (prvided via add-on) and Caddy (see here instead).
Change the Gunicorn port from 5000 to $PORT
The code to get DATABASE_URL in entrypoint.sh should probably not be needed.
Last but not least: create a heroku.yml file to point at the DF you want to use.
With docker-compose, you can re-use the same Dockerfile and change the entrypoint, but I don't think it's feasible with Heroku. You might need to create a duplicate the web Dockerfile and change it for your Celery dynos.
I've tried Docker on Heroku, but not with cookiecutter-django' setup. The Heroku way is not standard enough IMO, it's a bit of a middle ground between pure Heroku and bare Docker.
Hope that helps!
I am working on a project to customize the startproject command to create django projects from project_template, see below:
bootstrap/
├── __init__.py
├── conf
│ ├── __init__.py
│ └── project_template
│ ├── manage.py
│ ├── project_name
│ │ ├── __init__.py
│ │ ├── apps
│ │ │ ├── __init__.py
│ │ │ └── example
│ │ │ ├── __init__.py
│ │ │ ├── admin.py
│ │ │ ├── models.py
│ │ │ ├── tests.py
│ │ │ ├── urls.py
│ │ │ └── views.py
│ │ ├── contrib
│ │ │ └── __init__.py
│ │ ├── settings
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── development.py
│ │ │ └── production.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── requirements
│ │ ├── base.txt
│ │ ├── development.txt
│ │ └── production.txt
│ ├── requirements.txt
│ ├── static
│ │ ├── js
│ │ │ └── base.js
│ │ ├── scss
│ │ │ └── base.scss
│ │ └── vendor
│ │ └── README
│ └── templates
│ ├── 404.html
│ ├── 500.html
│ ├── base.html
│ └── example
│ ├── base.html
│ └── index.html
└── management
├── __init__.py
└── commands
├── __init__.py
└── startproject.py
this is the startproject.py
import os
import grabone as go
from django.core.management.commands.startproject import Command as StartprojectCommand
EXTENSIONS = ['py', 'txt', 'html', 'scss', 'css', 'js', 'bowerrc', 'rst']
class Command(StartprojectCommand):
def handle(self, project_name=None, target=None, *args, **options):
options['extensions'] += EXTENSIONS
return StartprojectCommand.handle(self, project_name=project_name, target=target, *args, **options)
def handle_template(self, template, subdir):
if template is None:
return os.path.join(go.__path__[0], 'conf', subdir)
return StartprojectCommand.handle_template(self, template, subdir)
When I run django-admin startproject test1 it creates the project folder etc etc, but it will try to parse the html templates and give me an error:
django.template.base.TemplateSyntaxError: 'staticfiles' is not a valid tag library: Template library staticfiles not found, tried django.templatetags.staticfiles
This is what the template looks like:
{% load staticfiles %}
<html>
...
</html>
This is what the INSTALLED_APPS in setting look like:
DJANGO_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
)
THIRD_PARTY_APPS = (
'django_extensions',
'pipeline',
# Add third party apps here
)
LOCAL_APPS = (
# Add local apps here
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
Some how the content in the settings is not being executed though...
removed html from
EXTENSIONS = ['py', 'txt', 'html', 'scss', 'css', 'js', 'bowerrc', 'rst']
Worked.