Django and Heroku: Static files work with 'foreman start' but not './manage.py runserver'
Asked Answered
H

3

2

I have added my own answer to the answers below, this has been solved.

I am able to serve up static files when powering up the server using the heroku tool foreman:

$ foreman start
12:25:21 web.1  | started with pid 33574
12:25:21 web.1  | 2013-04-10 12:25:21 [33577] [INFO] Starting gunicorn 0.17.2
12:25:21 web.1  | 2013-04-10 12:25:21 [33577] [INFO] Listening at: http://0.0.0.0:5000 (33577)
12:25:21 web.1  | 2013-04-10 12:25:21 [33577] [INFO] Using worker: sync
12:25:21 web.1  | 2013-04-10 12:25:21 [33582] [INFO] Booting worker with pid: 33582

but they static files aren't served up using runserver:

$ ./manage.py runserver
Validating models...

0 errors found
April 10, 2013 - 12:26:06
Django version 1.5, using settings 'myproject.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

My Procfile:

web: gunicorn myproject.wsgi

My settings.py (some settings removed):

import os
import logging

PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))

DEBUG = True
TEMPLATE_DEBUG = DEBUG

# Using local_settings for this
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        # The following settings are not used with sqlite3:
        'USER': '',
        'PASSWORD': '',
        'HOST': '',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
        'PORT': '',                      # Set to empty string for default.
    }
}

# Heroku specific database settings, overridden for local dev in local_settings.py (not in git)
import dj_database_url
DATABASES['default'] =  dj_database_url.config()

# Honor the 'X-Forwarded-Proto' header for request.is_secure() (also needed for Heroku)
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/var/www/example.com/media/"
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media')

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://example.com/media/", "http://media.example.com/"
MEDIA_URL = '/media/'

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/var/www/example.com/static/"
STATIC_ROOT = os.path.join(PROJECT_PATH, 'static')

# URL prefix for static files.
# Example: "http://example.com/static/", "http://static.example.com/"
STATIC_URL = '/static/'

# Additional locations of static files
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
#     'django.template.loaders.eggs.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.gzip.GZipMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.middleware.doc.XViewMiddleware',
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'myproject.urls'

# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'myproject.wsgi.application'

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    os.path.join(os.path.dirname(__file__), "templates"),
)

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.static",
    "django.core.context_processors.tz",
    "django.contrib.messages.context_processors.messages"
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'django.contrib.admindocs',
    'django.contrib.humanize',
    'django.contrib.flatpages',
    'debug_toolbar',
    'stripe',
    'notification',
    'south',
    'registration',
    'timedelta',
    'sorl.thumbnail',
    'django_messages',
    'tinymce',
)

try:
    from local_settings import *
except ImportError:
    pass

My main urls.py:

from django.conf.urls import patterns, include, handler500, url
from django.conf import settings
from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns(
    '',
    url(r'^$', 'myproject.views.root', name='root'),
    (r'^admin/', include(admin.site.urls)),

)

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

As the title says I'm able to load all my static assets using foreman start but not when running ./manage.py runserver.

I've also ran ./manage.py collectstatic so I know all the static files are in the correct directory.

My static and media folders both live under the myproject folder, as well as settings.py and the main urls.py.

Harryharsh answered 10/4, 2013 at 19:36 Comment(1)
For me this works for STATIC_URL='/static/', but not /site_media/static/. Even if I adjust urls.py accordingly, Django would not serve the files from this address. However, if I change one character in STATIC_URL, the particular files can be retrieved just fine --- though, of course, HTML files do not reference them correctly any longer. Yet changing /site_media/static/ to /static/ somehow makes it work. Not sure why...Lennox
S
3

You have to add the (absolute) path to the directory which contains your static files to STATICFILES_DIRS in the settings. You don't neet to run collectstatic

Scullery answered 10/4, 2013 at 20:16 Comment(3)
Thanks, I'll give that a try. I figured django.views.static.serve would solve the problem in my urls.py.Harryharsh
Got it working! I fiddled around with STATIC_ROOT and STATICFILES_DIRS and got it to work with runserver; I'll update my question.Harryharsh
In the future, or when your project matures, you should serve your static files from an S3 Bucket or what not -- not through your application server ;)Valverde
H
0

I finally got it working so that static files can be loaded via runserver and deploying to heroku also works.

Things I changed:

settings.py: Didn't change anything here, instead I will override some settings in my local_settings.py file.

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

# URL prefix for static files.
# Example: "http://example.com/static/", "http://static.example.com/"
STATIC_URL = '/static/'

# Additional locations of static files
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

local_settings.py: Added the following:

STATIC_ROOT = ''
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    os.path.join(PROJECT_PATH, 'static'),
)

This allows heroku to serve up your static files as well as runserver for development. It's also worth re-mentioning that I needed the extra static url patterns added to the end of my urls.py to get serving up static media in heroku.

Harryharsh answered 10/4, 2013 at 21:14 Comment(0)
S
-1

This is expected. Django doesn't serve static files. Heroku (apparently) does.

To serve files locally, you need to add a route in urls.py to serve the files.

Saltus answered 10/4, 2013 at 20:13 Comment(1)
I did at the end of my urls.py as posted.Harryharsh

© 2022 - 2024 — McMap. All rights reserved.