10

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',
)

Edit

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?

Edit2

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'),
)
Bentley4
  • 10,678
  • 25
  • 83
  • 134

5 Answers5

5

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

EDIT

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')

ANOTHER EDIT

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.

Francis Yaconiello
  • 10,829
  • 2
  • 35
  • 54
  • I changed some things after your answer, Could you check the edit of the original post? – Bentley4 Aug 16 '12 at 22:30
  • check it out again, i added some explanations. – Francis Yaconiello Aug 17 '12 at 17:23
  • once you changed your STATIC_ROOT did you `heroku run python manage.py collectstatic` ? could you add the output of collectstatic? – Francis Yaconiello Aug 17 '12 at 19:50
  • 1
    won't work with heroku, cf. [ephemeral filesystem](https://devcenter.heroku.com/articles/dynos#isolation-and-security), also just answered @Bentley4 's other question http://stackoverflow.com/a/12014658/343834 – Maxime R. Aug 18 '12 at 00:25
  • In the past I ran collectstatic as part of my web worker startup (in the procfile) so anytime a webworker was starting or restarting it would collect my static files leading to my not being inconvenienced by the ephemeral filesystem. I would actually recommend S3 and the django storages app (use S3 Boto) for getting past this. – Francis Yaconiello Aug 23 '12 at 15:47
  • After trying everything, nothing worked, until you gave me the idea of restarting the dyno. Thanks, it works now. – Lawrr Oct 21 '15 at 12:20
  • wow this is old, is hosting django sites with heroku still a PIA? – Francis Yaconiello Oct 22 '15 at 13:40
4

There is one solution.

In urls.py add:

from django.conf import settings

urlpatterns += patterns('',
    (r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
)

p.s. For STATIC_URL = '/static/'

AlexanderLedovsky
  • 727
  • 1
  • 6
  • 18
1

Use the run_collectstatic script which run as part of the post_compile provided by heroku-django-cookbook. It makes use of the post_compile hook provided by the Heroku python buildpack

manojlds
  • 290,304
  • 63
  • 469
  • 417
1

I ran into the same problem; it seems you need these three settings in particular:

  1. STATIC_ROOT must be defined in your settings.py, for example:

    STATIC_ROOT = os.path.join(PROJECT_PATH, 'served/static/')
    

    Where PROJECT_PATH is your project root (in your case, the absolute path to the myproject_django directory.

  2. Similarly, STATIC_URL must also be set (Django will throw an ImproperlyConfigured error anyway, if you don't). Your current setting of '/static/' is fine.

  3. In your root urls.py, configure the static urls:

    from django.conf import settings
    from django.conf.urls.static import static  
    
    ...
    
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    

Finally, run python manage.py collectstatic; this will copy all the files from /path/to/site-packages/django/contrib/admin/static/admin/ to /served/static/. (You can read more about how Django serves static files here).

Now when you run foreman start, you should see the admin with styling.

Don't forget to add served/static/ to your .gitignore!

3cheesewheel
  • 9,133
  • 9
  • 39
  • 59
0

I found here good way to resolve all my problems with Django on heroku

chuckis
  • 1
  • 1