Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referencing image in CSS with relative path doesn't work in Django

I am using Django 1.3 with built-in static app.

My static folder structure is like this:

static/
    css/
       main.css
       img/
    js/

So I tried to reference images under static/css/img/ folder from CSS like this:

background:url('img/btn_white.gif') repeat-x;

But the images don'e show up. When I inspect elements in Chrome, I found the image path to be http://localhost/mysite/static/css/main.css/img/btn_white.gif/

Which is very wierd since this relative path should have referenced static/css/ folder instead of main.css. So I tried to change path to be url('../img/btn_white.gif'), and it works in Chrome and Firefox but not in IE.

I am pretty sure this problem is related to Django, because in my pure HTML/CSS, this relative path works just fine. I also tried to put css in media folder and the problem is the same.

My settings related to static app:

in settings.py:

STATIC_ROOT = os.path.join(os.path.dirname(__file__),'static').replace('\\','/')
STATIC_URL = 'http://localhost/mysite/static/'

in urls.py:

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

Related question: Is a relative path in a CSS file relative to the CSS file?

like image 786
Yifu Avatar asked Jun 12 '11 05:06

Yifu


1 Answers

The problem is caused by your URLconf, specifically the pattern:

r'^static/(?P<path>.*)/$'

This means that a the URL must end in a forward slash for it to match this pattern. i.e. the following URL will not match: (because it doesn't have a trailing slash)

/mysite/static/css/main.css

The weird thing, is that it does work. The reason for this is Django's APPEND_SLASH setting:

When set to True, if the request URL does not match any of the patterns in the URLconf and it doesn't end in a slash, an HTTP redirect is issued to the same URL with a slash appended. Note that the redirect may cause any data submitted in a POST request to be lost.

So when your browser makes a request to:

/mysite/static/css/main.css

…Django will fail to match it against any of the URLs, and will issue a redirect to: (because APPEND_SLASH defaults to True)

mysite/static/css/main.css/

This new request will succeed and your browser will now be able to download the CSS file, however the CSS file's resource URL now ends with a slash. When your browser processes the CSS rules and comes across:

background:url('img/btn_white.gif') repeat-x;

It will attempt to join that relative URI to the URI of the CSS resource. e.g.:

/mysite/static/css/main.css/ + img/btn_white.gif = /mysite/static/css/main.css/img/btn_white.gif

This will fail, so your browser will get a redirect to: (again because of APPEND_SLASH)

/mysite/static/css/main.css/img/btn_white.gif/

But obviously that too will fail.

Solutions

Change your URL pattern to the following: (note the removed trailing / in the pattern)

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

Or use one of the recommended methods:

from django.conf import settings

if settings.DEBUG:
    urlpatterns += patterns('django.contrib.staticfiles.views',
        url(r'^static/(?P<path>.*)$', 'serve'),
    )

…or:

from django.contrib.staticfiles.urls import staticfiles_urlpatterns

# ... the rest of your URLconf here ...

urlpatterns += staticfiles_urlpatterns()
like image 139
bradley.ayers Avatar answered Oct 07 '22 13:10

bradley.ayers