knite
knite

Reputation: 6171

Serving root-level static files on Heroku with Django?

I need to serve several root-level static files on Heroku (eg, domain.com/favicon.ico). Here's the list of files as it currently stands:

favicon.ico
crossdomain.xml
sitemap.xml
robots.txt
humans.txt
apple-touch-icon-57x57-precomposed.png
apple-touch-icon-57x57.png
apple-touch-icon-72x72-precomposed.png
apple-touch-icon-72x72.png
apple-touch-icon-114x114-precomposed.png
apple-touch-icon-114x114.png
apple-touch-icon-precomposed.png
apple-touch-icon.png

I've searched high and low and can't find a standard way to serve a large set of static files. Wherever I host them (on Heroku with collectstatic or Amazon S3), explicitly defining and redirecting 14 files in my urls.py seems incorrect.

Upvotes: 16

Views: 2396

Answers (4)

neoneye
neoneye

Reputation: 52201

I'm using Django 5.x on Heroku.

At first I tried serving files from the root dir without using 302 redirects into the static dir controlled by whitenoise. However it was too troublesome.

My second attempt is inspired by these neat solutions: A, B.

Example: /favicon-32x32.png redirects to /static/favicon-32x32.9e902d163167.png.

Place favicon related files inside the static dir, and run python manage.py collectstatic.

Here is a snippet of urls.py.

from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic import RedirectView

def favicon_urlpatterns():
    names = [
        'android-chrome-192x192.png',
        'android-chrome-384x384.png',
        'apple-touch-icon.png',
        'browserconfig.xml',
        'favicon-16x16.png',
        'favicon-32x32.png',
        'favicon.ico',
        'mstile-150x150.png',
        'safari-pinned-tab.svg',
        'site.webmanifest'
    ]
    urlpatterns = []
    for name in names:
        item = path(name, RedirectView.as_view(url=staticfiles_storage.url(name)))
        urlpatterns.append(item)
    return urlpatterns

# At the bottom of urls.py
urlpatterns += favicon_urlpatterns()

Upvotes: 0

Bruno A.
Bruno A.

Reputation: 1875

Despite this is being an old question, I still have the problem. I like the way the URLs are generated from a list in the current solution, but I was not convinced that was the best.

After a bit of research though, I found realfavicongenerator.net being a very useful resources which generates all the required favicons files for you and I was sent this post by a colleague which seems to support the proposed solution, with a more recent Django version.

Based on all the above, my solution is using native sitemap framework, django-robots for robots.txt and a ROOT_ASSETS dictionary, with files prefix as key, and values as a list of files, for example:

ROOT_ASSETS = {
    "images/favicons/": [
        "apple-touch-icon-114x114.png",
        "apple-touch-icon-120x120.png",
        "apple-touch-icon-144x144.png",
        "apple-touch-icon-152x152.png",
        "apple-touch-icon-180x180.png",
        "apple-touch-icon-57x57.png",
        "apple-touch-icon-60x60.png",
        "apple-touch-icon-72x72.png",
        "apple-touch-icon-76x76.png",
        "apple-touch-icon-precomposed.png",
        "favicon.ico",
    ]
}

Then I generate my urls with:

from django.conf.urls import patterns, url, include
from django.contrib.staticfiles.storage import staticfiles_storage

root_assets_urls = []
for prefix, files in ROOT_ASSETS.iteritems():
    for f in files:
        asset_url = staticfiles_storage.url("{prefix}{file}".format(prefix=prefix, file=f))
        root_assets_urls.append(
            url(r'^{0}$'.format(f), RedirectView.as_view(url=asset_url))
        )
root_assets = patterns('', *root_assets_urls)

urlpatterns = patterns(
    '',
    url(r'^', include(root_assets)),
    [...]
)

I'm also including the HTML generated by realfavicongenerator.net in my master template's head.

Upvotes: 2

b1_
b1_

Reputation: 2126

I didn't find any url config files, so I think heroku not provide this service.

And according to official docs you need save your data on external services

EDIT:

So according to heroku docs only 301 redirects to S3 can help you. Or even better for all media (ico, favicons, png and another images) files in templates set absolute path to S3 services and for robots and crossdomain.xml in urls.py set 301 redirects to S3. For sitemap.xml better use native solutions

It is not wrong to use right redirects codes in development.

Upvotes: 1

knite
knite

Reputation: 6171

This is my current solution. Feedback appreciated.

from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from settings import STATIC_URL, ASSETS, DEBUG, AWS_STORAGE

#ASSETS is a tuple: ('favicon.ico, 'robots.txt', ...)    
urls = [('^%s$' % f, 'redirect_to', {'url': STATIC_URL + f}) for f in ASSETS]
urlpatterns += patterns('django.views.generic.simple', *urls)

#Serve static files from runserver if in dev mode with S3 off.
if DEBUG and not AWS_STORAGE:
    urlpatterns += staticfiles_urlpatterns()

Upvotes: 4

Related Questions