21

This question seems to be asked several time but I can not fix it.

I deployed a django app on production with DEBUG = False. I set my allowed_host. I used {% load static from staticfiles %} to load static files. I exactly write the settings sugested by Heroku doc :

BASE_DIR = os.path.dirname(os.path.dirname(__file__))
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))

STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(PROJECT_ROOT, 'static'),
)

STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

BUT I got an error 500. And got this traceback (by mail)

...
`cache_name = self.clean_name(self.hashed_name(name))
 File "/app/.heroku/python/lib/python3.5/site-    packages/django/contrib/staticfiles/storage.py", line 94, in hashed_name (clean_name, self))
...
ValueError: The file ‘app/css/font.css’ could not be found with <whitenoise.django.GzipManifestStaticFilesStorage object at 0x7febf600a7f0>.`

When I run heroku run python manage.py collectstatic --noinput All seems ok :

276 static files copied to '/app/annuaire/staticfiles', 276 post-processed.

Does anyone have an idea to help me, please ?

Thanks

EDIT :

annuaire
|-- /annuaire
|-- -- /settings.py
|-- /app
|-- -- /static/...`

wsgi.py

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise


application = get_wsgi_application()
application = DjangoWhiteNoise(application)
vpoulain
  • 740
  • 1
  • 7
  • 18
  • 1
    Django only usually calls that particular function when DEBUG=False so I'm puzzled that you could get that error with DEBUG=True. I'd suggest testing your app locally with DEBUG=False, running `collectstatic` and then `runserver` and see if you get that error. Could it be that you just haven't committed that particular file? – D. Evans Feb 19 '16 at 14:11
  • Sorry! When Debug is False, you are right! – vpoulain Feb 19 '16 at 14:13
  • Have you printed `STATIC_ROOT` to ensure it is the same as '`/app/annuaire/staticfiles'`? – agconti Feb 19 '16 at 14:21
  • I just did it (locally) I got `In [3]: settings.STATIC_ROOT Out[3]: '/Users/vincentpoulain/xxxx/annuaire/annuaire/staticfiles'` :/ – vpoulain Feb 19 '16 at 14:24
  • I tried to change to `STATIC_ROOT = os.path.join(BASE_DIR, '../app/staticfiles')` – vpoulain Feb 19 '16 at 14:27
  • It does not works... & now when I run collectstatic on heroku I got `FileNotFoundError: [Errno 2] No such file or directory: '/app/annuaire/static'` – vpoulain Feb 19 '16 at 14:32
  • Out of curiosity, try a different storage backend. `STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'` – Ben Feb 19 '16 at 17:03
  • Already tried. Does not work :/ – vpoulain Feb 19 '16 at 17:18
  • After `collectstatic` I don't have any staticfiles folder in heroku... – vpoulain Feb 19 '16 at 17:19
  • You need to get things working locally with DEBUG=False before you try pushing to Heroku as that only complicates things. I don't think this is a settings problem as your original settings looked fine. I think it's probably that the `app/css/font.css` file is missing or in the wrong place. – D. Evans Feb 19 '16 at 17:24
  • My `/` page does not work whule `/admin` is well rendered. Moreover, I check and my static files can be returned by the web server: `http://localhost:8000/static/app/style.css` returns a HTTP 200. In my console displays `"GET / HTTP/1.1" 500 27` – vpoulain Feb 24 '16 at 09:56
  • Okay, now it works locally but still does not work on heroku. I have nothing to debug, crazy – vpoulain Feb 24 '16 at 10:37
  • I just added an answer that works for Django 2>= and whitenoise 4>= – lmiguelvargasf Dec 09 '18 at 07:19

10 Answers10

10

With DEBUG=False, what originals use to work does not work for me anymore.

However a fix by enabling whitenoise on MIDDLEWARE in settings.py solved it. Best to be just below SecurityMiddleware.

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware', # add this line
    #Other middleware...
]

```

According to the docs, it actually needs to be enabled in the first place.

Zac Kwan
  • 5,587
  • 4
  • 20
  • 27
  • This worked for me. In heroku's launch django instructions they say to include it https://devcenter.heroku.com/articles/django-assets, but I started with their heroku-django-template https://github.com/heroku/heroku-django-template and it was not included in that – amchugh89 Aug 15 '18 at 15:46
7

I got it. I needed to add

python manage.py collectstatic --noinput;

in my Procfile. Heroku doc said that collecticstatic is automatically triggered. https://devcenter.heroku.com/articles/django-assets

Thanks

wowkin2
  • 5,895
  • 5
  • 23
  • 66
vpoulain
  • 740
  • 1
  • 7
  • 18
  • 4
    or just remove the environmental variable `DISABLE_COLLECTSTATIC` from your app settings through the [dashboard](https://id.heroku.com/login). What it's important is this: Do NOT turn its value to 0, just delete this env variable completely. In that way you should not have to edit your `Procfile`. Then, all should work (at least they worked for me!). Credits go to: [YunoJuno](http://tech.yunojuno.com/django-whitenoise-and-heroku-s-ephemeral-filesystem). – nik_m Nov 07 '16 at 11:21
  • @YunoJuno thanks man... Hours spent trying to debug this s*** and you just saved me! – Julien Séveno-Piltant Apr 03 '19 at 11:57
5

For me following worked.

settings.py

DEBUG = True

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') #this is not used
# Add static folder to STATIC_DIRS
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

urls.py

from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [

] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Note

This helper function works only in debug mode and only if the given prefix is local (e.g. /static/) and not a URL (e.g. http://static.example.com/).

Also this helper function only serves the actual STATIC_ROOT folder; it doesn’t perform static files discovery like django.contrib.staticfiles.

Kishor Pawar
  • 3,386
  • 3
  • 28
  • 61
3

The problem is that the Python application in Heroku uses the built-in web server and does not serve static files.

You can use the app of the whitenoise, this working solution is 100%.

Suppose you have already generated static files, for example:

$ python manage.py collectstatic

Next you need to do this:

1) $ pip install whitenoise

2) add string "whitenoise==3.3.0" in your requirements.txt

3) add code in settings.py

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

4) add this code in app/wsgi.py

from whitenoise.django import DjangoWhiteNoise
application = DjangoWhiteNoise(application)
I. S.
  • 31
  • 1
2

for BASE_DIR you need to a double dirname if your settings are not in the root but in /projectname/ folder :

settings.py

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
# for /static/root/favicon.ico    
WHITENOISE_ROOT = os.path.join(BASE_DIR, 'staticfiles', 'root') 

template.html

{%  load staticfiles %}
<link rel="stylesheet" href="{%  static "app/css/font.css" %}">

app tree for this example:

annuaire
|-- /annuaire
|-- -- /settings.py
|-- /app
|-- /static/app/css/font.css
Meska
  • 181
  • 1
  • 6
  • Thanks! I did it but it still does not work... I edited my django app tree in main question post. – vpoulain Feb 19 '16 at 16:29
  • It so weird when I collectstatic I got `275 static files copied to '/app/staticfiles', 1 unmodified, 276 post-processed.` but on heroku bash: staticfiles is still empty ... – vpoulain Feb 19 '16 at 17:08
  • @vpoulain That's because each new Heroku process runs in its own ephemeral filesystem, so the new files won't be seen by any other process. (See https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem). `collectstatic` must be run during the initial push for the files to be persisted. – D. Evans Feb 19 '16 at 17:19
  • @vpoulain check the app tree, for your code i think you need to use STATICFILES_DIRS = ( os.path.join(BASE_DIR,'app','static'), ) or move static folder to the root – Meska Feb 19 '16 at 18:03
  • @Meska this is bit confusing, where to write `staticfiles` and where to write `static`? – Talha Anwar Jul 16 '20 at 13:29
2

In addition to above answers, it can also be that you have not specified a correct STATIC_ROOT as described in https://docs.djangoproject.com/en/2.0/howto/static-files/#deployment

For me, the solution was adding this to the end of my production settings.py

STATIC_ROOT = "/app/static/"

To know where your static folder is in your heroku run this

heroku run python manage.py collectstatic

Then you will see the path being shown there.

Truc
  • 616
  • 6
  • 5
1

I struggled a couple of hours until I finally figured out the problem. The main problem in my opinion is that in the Heroku official documentation they use the Old-style middleware that uses MIDDLEWARE_CLASSES which is deprecated, instead of the new MIDDLEWARE setting.

In whitenoise version 4+, the WSGI integration option for Django (which involved editing wsgi.py) has been removed. Instead, you should add WhiteNoise to your middleware list in settings.py and remove any reference to WhiteNoise from wsgi.py. (from the docs)

The following configuration worked like a charm:

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'

MIDDLEWARE = [
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    # the next line of code is the one that solved my problems
    'whitenoise.middleware.WhiteNoiseMiddleware',

]

Pay attention to the following Note, also from the docs.

You might find other third-party middleware that suggests it should be given highest priority at the top of the middleware list. Unless you understand exactly what is happening you should ignore this advice and always place WhiteNoiseMiddleware above other middleware.

lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
1

I have had the same issue. The simplest way to find the problem is to use

heroku run ls staticfiles/images

if images is in the directory where your files should be. This will give you a list of all the files in that directory.

As I found out it was a case issue in the file extension. The file had an extension .JPG and I referenced it on the template with an extension .jpg

ysf
  • 4,634
  • 3
  • 27
  • 29
1

$ pip install whitenoise

add whitenoise in middleware.

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
]

also need to add STATIC_ROOT in setting.py

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

and add media_root in urls.py

from django.conf import settings

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
        + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

and then you can run collectstatic command locally or on server python manage.py collectstatic

and it will work properly. you can run this command locally collectstatic and it will work on server.

0

this is worked for me

my requirements.txt is

whitenoise==6.2.0
static3==0.7.0
webdav4==0.9.7
Django==3.2
# others

I delete STATIC_ROOT in settings.py

and add var STATICFILES_DIRS, my settings.py :


MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    "whitenoise.middleware.WhiteNoiseMiddleware",
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

STATIC_URL = 'static/'

if you set heroku config:set DISABLE_COLLECTSTATIC=1, now you should run properly

if you still want use COLLECTSTATIC function add it manually in Procfile file as:

web: python manage.py collectstatic --no-input; gunicorn my_blog.wsgi --log-file - --log-level debug

my my_blog.wsgifile is(it's configed by following a post which cannot be found now):

import os
from django.core.wsgi import get_wsgi_application
from dj_static import Cling

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'my_blog.settings')
application = Cling(get_wsgi_application())
KSroido
  • 61
  • 8