1
votes

As the title states, I am lost here because I can upload files to MEDIA_ROOT via the site, but when I attempt to serve them I get a 404 error. The most annoying part is that this worked for ages, now something changed and it's broken.

UPDATE: I've narrowed the problem down.

If I change: MEDIA_URL = '/media/'

Django serves the file at http://192.168.xxx.xxx/media/media/file.txt

If I change: MEDIA_URL = '/kittens/'

Django serves the file at http://192.168.xxx.xxx/kittens/file.txt

runserver output:

urls.py MEDIA_URL: /media/
urls.py MEDIA_ROOT:
Settings.py MEDIA_ROOT: /home/user/kittens/

What in the world is going on? Why the "nested" media url path? django.conf.settings.MEDIA_ROOT is blank while mysite.settings.MEDIA_ROOT is not?

urls.py

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = patterns('',
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

print 'urls.py MEDIA_URL: %s' % (settings.MEDIA_URL)
print 'urls.py MEDIA_ROOT: %s' % (settings.MEDIA_ROOT)

settings.py

MEDIA_URL = '/media/'
MEDIA_ROOT = '/home/user/kittens/'

print 'Settings.py MEDIA_ROOT: %s' % (MEDIA_ROOT)

On the disk

drwxr-xr-x 0 user user     0 Mar 11 11:00 kittens/
-rwxr-xr-x 0 user user 22561 Oct  5 19:17 kittens/file.txt*

In the browser

Page not found (404)
Request Method:     GET
Request URL:    http://192.168.../media/file.txt

"file.txt" does not exist

python manage.py runserver

[11/Mar/2014 15:00:43] "GET /media/file.txt HTTP/1.1" 404 1629

python manage.py shell

IPython 1.1.0 -- An enhanced Interactive Python.

In [1]: from django.conf import settings

In [2]: settings.MEDIA_ROOT
Out[2]: 'kittens/'

In [3]: settings.MEDIA_URL
Out[3]: '/media/'

In [8]: os.path.join(settings.MEDIA_ROOT, 'file.txt')
Out[8]: 'kittens/file.txt'

In [9]: os.path.exists(os.path.join(settings.MEDIA_ROOT, 'file.txt'))
Out[9]: True
2
Why is file.txt executable? Did you try after removing that attribute? - Selcuk
It's a mounted NTFS share so the perms are stuck like that. BUT, that's not the issue, 1) That has been the config since the beginning (when it worked), 2) To verify I moved the media path to the local filesystem with perms rw and it still fails to serve the file. - James
MEDIA_ROOT is absolute on my box. I'll update the question to reflect that. - James

2 Answers

2
votes

The problem was isolated by printing the configuration parameters, i.e.:

settings.py

MEDIA_URL = '/media/'
MEDIA_ROOT = '/home/user/kittens/'

print 'Settings.py MEDIA_ROOT: %s' % (MEDIA_ROOT)

urls.py

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = patterns('',
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

print 'urls.py MEDIA_URL: %s' % (settings.MEDIA_URL)
print 'urls.py MEDIA_ROOT: %s' % (settings.MEDIA_ROOT)

python manage.py runserver

urls.py MEDIA_URL: /media/
urls.py MEDIA_ROOT:
Settings.py MEDIA_ROOT: /home/user/kittens
Validating models...

You'll notice the urls.py MEDIA_ROOT is blank. After inspecting settings.py I noticed that the root url configuration was being called before MEDIA_ROOT was configured. Therefore, changing the order fixed the problem.

settings.py

# Must specify MEDIA_ROOT first so urls.py picks it up via django.conf.settings
MEDIA_ROOT = '/home/user/kittens'
# Then call site root's urls.py
ROOT_URLCONF = 'mysite.urls'

I don't know how this caused the "nested" media path, but the change did fix it regardless. That is, I can navigate to http://192.168.xxx.xxx/media/file.txt.

1
votes

As per django documentation, MEDIA_ROOT must be absolute path:

MEDIA_ROOT

Default: '' (Empty string)

Absolute filesystem path to the directory that will hold user-uploaded files.

Example: "/var/www/example.com/media/"

So your configuration should be something like this if you want media to be inside your project:

MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'kittens/')

or an absolute path:

MEDIA_ROOT = /user/uploaded/files/kittens/

Edit: Since you updated your question above answer is not relevant. But I can see problem with your url config where you configure the media path twice:

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

the second line should be enough..