8

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?

5
  • Include the <link> tag you're using in your template. Commented Jun 12, 2011 at 5:59
  • @bradley.ayers <link type="text/css" rel="stylesheet" href="{{ STATIC_URL }}css/main.css" /> Commented Jun 12, 2011 at 14:38
  • Hmm, I just realized that you are showing a structure of static/css/img. Did you mean for img to be below css directory, or side-by-side? If that's intentional, you might try moving it up a level, then the url(../img/btn.gif) syntax would be correct. Commented Jun 12, 2011 at 21:23
  • like bradley said - if an Answer solves your Question, you ought to checkmark it. Commented Jun 19, 2011 at 15:49
  • sorry I didn't know. Already marked it several days ago. Commented Sep 15, 2011 at 11:00

1 Answer 1

9

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()
Sign up to request clarification or add additional context in comments.

5 Comments

That makes sense - I've had more problems with when you should or should not have trailing slashes...
Hopefully my write-up makes it a bit clearer what's going on :)
Thanks, that's exactly the problem! I solved it by eliminating the slash in my original url setting. But for the two suggested ways you gave me, the first one won't work. The second one has import error in Django 1.3.
@Yifu it works fine for me on Django 1.3, open a new question if you want to explore that problem.
I've spent much more time slashing Django than I'd like. Nice explanation +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.