Michael Johnston
Michael Johnston

Reputation: 2382

Adding expire header for Django static files on Heroku

I'm trying to optimize my webpage and am having trouble setting expiration date headers on my static files.

I am running django-1.5, python-2.7.3.

Here's my cache settings in settings.pyso far:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': os.path.join(PROJECT_ROOT, 'cache/'),
    }
}

CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 5 * 60
CACHE_MIDDLEWARE_KEY_PREFIX = ''

MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    ...
    'django.middleware.cache.FetchFromCacheMiddleware',
)

And my static file settings in settings.py:

import os.path

PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_ROOT = os.path.abspath(os.path.join(PROJECT_DIR, '..'))

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

STATIC_URL = '/static/'

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

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

The closest advice I've found was here, but I'm unable to modify the .htaccess files on Heroku.

Any help is greatly appreciated. Thanks!

Upvotes: 4

Views: 3303

Answers (3)

gitaarik
gitaarik

Reputation: 46300

In production you shouldn't serve static files with Django. See the warning boxes on this page: https://docs.djangoproject.com/en/1.4/ref/contrib/staticfiles/#static-file-development-view

In development, Django's contrib.staticfiles app automatically serves staticfiles for you by overwriting the runserver command. This way you can't control the way it serves the static files.

You can prevent the staticfiles app from serving the static files by adding the --nostatic option to the runserver command:

./manage.py runserver --nostatic

Then you can write an url config to manually serve the static files with headers you want:

from functools import wraps
from django.conf import settings
from django.contrib.staticfiles.views import serve as serve_static
from django.conf.urls import patterns, url

urlpatterns = patterns('', )

if settings.DEBUG:

    def custom_headers(view_func):

        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            response = view_func(request, *args, **kwargs)
            response['Custom-header'] = 'Awesome'
            response['Another-header'] = 'Bad ass'
            return response

        return wrapper

    urlpatterns += patterns('',
        url(r'^static/(?P<path>.*)$', custom_headers(serve_static)),
    )

If you want your manage.py to have the --nostatic option on by default, you can put this in your manage.py:

if '--nostatic' not in sys.argv:
    sys.argv.append('--nostatic')

Upvotes: 1

dusual
dusual

Reputation: 2207

I think since you are hosting your project on heroku , the generally accepted practice seems to be using S3 for serving static files.

Have a look at this question : Proper way to handle static files and templates for Django on Heroku

I am not too sure about this but I am sure you should be able to change headers while serving files from S3 atleast this SO question seems to suggest that way Is it possible to change headers on an S3 object without downloading the entire object?

Hope this helps

Upvotes: 0

Jack Shedd
Jack Shedd

Reputation: 3531

The django staticfiles app does not provide out of the box support for custom headers. You'll have to hack together your own view to serve up the files and add custom headers to the HttpResponse.

But You should not be serving your static files using Django. This is a terrible idea.

  1. Django is single-threaded, and blocking. So every time you're serving a user a static file, you're literally serving nothing else (including your application code, which is what Django is there for).
  2. Django's staticviews file is insecure, and unstable. The documentation specifically says not to use it in production. So do not use it in production. Ever.

Upvotes: 6

Related Questions