My Django 1.3 project serves the static files on a development server but with the gunicorn server static files are not served. I followed the steps of this Heroku guide.
When I used the contents of my procfile like in the guide (
web: gunicorn myproject_django.wsgi -b 0.0.0.0:$PORT
) my project was not recognised by Heroku.
Then I changed that Procfile to this:
web: python myproject_django/manage.py run_gunicorn -b 0.0.0.0:$PORT -w 3
Now my app runs except for the static files(css not active nor images).
My project tree:
.
├── Procfile
├── myproject_django
│ ├── core
│ │ ├── admin.py
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── base.css
│ │ │ │ ├── layout.css
│ │ │ │
│ │ │ └── media
│ │ │ ├── pek.ico
│ │ │ ├── pek.png
│ │ │ ├── pek_symbol.png
│ │ ├── tests.py
│ │ └── views.py
│ ├── __init__.py
│ ├── manage.py
│ ├── settings.py
│ ├── templates
│ │ └── core
│ │ ├── home.html
│ │ └── install.html
│ └── urls.py
└── requirements.txt
Potentially relevant parts of settings.py
MEDIA_ROOT = ''
MEDIA_URL = '/static/media'
STATIC_ROOT = ''
STATIC_URL = '/static/'
ADMIN_MEDIA_PREFIX = '/static/admin/'
STATICFILES_DIRS = (
os.path.abspath(__file__)+'/..'+'/myproject_django/core/static',
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'core',
'gunicorn',
'django.contrib.admin',
)
I adjusted the following things after Francis Yaconiello's entry:
In settings.py
STATIC_ROOT = os.path.join(os.getcwd(),'core/static')
STATICFILES_DIRS = ( os.path.abspath(__file__)+'/..'+'/core/static', )
In gitignore:
staticfiles/*
Then commited.
And finally ran heroku run python myproject_django/manage.py collectstatic
.
But static files are still not served when I check the webpage. Given my directory tree why didn't these changes work?
I still don't see my static files. When I click on an image while DEBUG=True
I get this:
Request URL: http://myproject.herokuapp.com/static/media/pek.png
Tree (Note that the staticfiles
dir is empty)
.
├── Procfile
├── myproject_django
│ ├── admin
│ ├── core
│ │ ├── admin.py
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── base.css
│ │ │ │ ├── layout.css
│ │ │ └── media
| | | ├── pek.ico
| │ │ ├── pek.png
| │ │ ├── pek_symbol.png
│ │ ├── tests.py
│ │ ├── views.py
│ ├── __init__.py
│ ├── manage.py
│ ├── settings.py
│ ├── staticfiles
│ ├── templates
│ │ └── core
│ │ ├── 404.html
│ │ ├── 500.html
│ │ ├── home.html
│ │ └── install.html
│ ├── urls.py
└── requirements.txt
In settings.py
PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'static/media')
STATIC_ROOT = os.path.join(PROJECT_PATH,'staticfiles')
STATICFILES_DIRS = (
os.path.join(PROJECT_PATH, 'core/static'),
)
Gunicorn is meant to serve dynamic content, it should not be used to serve static files.
Storing static files elsewhere is crucial for Heroku apps since dynos have an ephemeral filesystem. Whenever you replace a dyno or when it restarts, which happens daily, all files that aren't part of your application's slug are lost. Use a storage solution like S3 to offload the storage of static files from your app.
Collectstatic during builds When a Django application is deployed to Heroku, $ python manage.py collectstatic --noinput is run automatically during the build. A build will fail if the collectstatic step is not successful.
Configuring static filesMake sure that django.contrib.staticfiles is included in your INSTALLED_APPS . In your templates, use the static template tag to build the URL for the given relative path using the configured STATICFILES_STORAGE . Store your static files in a folder called static in your app.
Specify your STATIC_ROOT
I generally set it to :
import os
STATIC_ROOT = os.path.join(os.getcwd(), "staticfiles")
create that directory in your project
mkdir staticfiles
make sure that the contents of staticfiles is not git tracked
nano .gitignore
add
staticfiles/*
then commit it and push to heroku.
lastly,
heroku run python manage.py collectstatic
STATIC_ROOT = os.path.join(os.getcwd(),'core/static')
STATICFILES_DIRS = ( os.path.abspath(__file__)+'/..'+'/core/static', )
These two settings cannot be the same thing.
STATICFILES_DIR
is OK, if redundant your STATICFILES_FINDERS
already is telling it to find staticfiles in the static
directory of each app with this: 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
The point of STATIC_ROOT
is to provide a new directory completely separate from your project that you can serve with a third party server like nginx. Which is why you created that directory staticfiles
:
STATIC_ROOT = os.path.join(os.getcwd(),'staticfiles')
workaround for ephemeral filesystem
Each dyno gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the dyno’s lifetime its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other dyno and any files written will be discarded the moment the dyno is stopped or restarted.
which means that as long as you collectstatic on each dyno instance during web startup, you won't have any issues.
web: python myproject_django/manage.py collectstatic --noinput; python myproject_django/manage.py run_gunicorn -b 0.0.0.0:$PORT -w 3
That said, I currently use S3 and django storages http://django-storages.readthedocs.org/en/latest/index.html. Its fairly easy (and cheap) to get this going.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With