tags:

views:

44

answers:

3

I want to serve files dynamically from behind the root of my web directory. Currently I'm serving all the files statically which I did just in order to include my javascripts and css files. I realize this is probably dumb but I'm not able to serve files any other way!

So, I want to serve files dynamically, without the user being able access at another time just by using a url.

My settings

ADMIN_MEDIA_PREFIX = '/media/'
MEDIA_ROOT = os.path.join( APP_DIR, 'site_media' )
MEDIA_URL = 'http://localhost:8000/site_media/'

My URLS

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

Thanks!

+2  A: 

What do you mean by "dynamically"? What is it that you're trying to achieve? Do you want to control access to the files?

If you want to run some Django-view that decides whether the user is allowed access to the file or not, you can use sendfile. See the following snippet for code on how to set the correct headers: http://djangosnippets.org/snippets/2226/

Your webserver also needs to support this header, at least apache and nginx which I've worked with does.

You also need to think about how to store and distribute the files as the server that is running the webserver needs access to the files. This will depend on your setup.

knutin
Yes, I want to control access to the files. For instance, say I want only superusers to be able to download a particular PDF. I want to insure the user has those credentials before allowing them to download the file. I do *not* want to allow anyone to just go to /some/url.pdf to grab the file without being authenticated.
Paperino
Then using the sendfile functionality of web servers will be perfect as you can handle the permissions in the exact same way as you handle permissions to the rest of your project. This solution also awoids reading the file into your Django process just so you can later write it back to the web server.
knutin
Just saw your comment on your question.. You can easily whatever you like when you decide to let the user download the file or not. For example: Has this file been downloaded by this user before? Should I charge this user for every download? Etc.
knutin
A: 

There is no absolute way to protect your files from "being accessed directly" (unless you require users to login to see your CSS/JS/Logo or something). You can throw 403 Forbidden errors at requests with no referrer, but this will only break things and not make your files any more secure.

Robus
+1  A: 

You could obfuscate the URLs in such a way that it'd be pretty hard to guess; this isn't at all secure but it would stop the casual poker-arounder. You'd also need to ensure that whatever you use to serve static media in production isn't set to display directory listings.

If you need something a little more secure, here's what I've done in the past:

In models.py:

my_storage = FileSystemStorage(location=settings.MY_FILES_ROOT, base_url='DO_NOT_USE')

class Resource (models.Model):
    //...snip...
    resource_file = models.FileField(storage = my_storage)

where settings.MY_FILES_ROOT is a path outside of where you keep your static files normally.

Then, in views.py:

def get_file(request, whatever_id):
    //check if the user is allowed to access the file here
    resource = Resource.objects.get(id=resid)
    response = HttpResponse(resource.resource_file.read(), mimetype='text/whatever')
    response['Content-Disposition'] = 'attachment; filename=whatever.ext'
    return response

Of course, this approach only works if you know the MIME type and file extension of the file, whether it's always the same (the app I did this in always served PDFs) or you extract it from the file.

Adam Brenecki
URL obfuscation is clever but not really what I'm after. I'm trying to prevent users direct linking documents that should require authentication to view.
Paperino
Sorry, apparently the enter key sends what you are writing immediately. Your 2nd option is interesting and is something I've been looking at but hoped there were better alternatives. Maybe this: http://djangosnippets.org/snippets/365/ is even a better solution? Thanks for your response!
Paperino
The FileWrapper sounds like a good idea. (I should note that the `Content-Disposition` header (which is not in that snippet) is only necessary if you want the user to download a file (instead of viewing it inline or in a browser plugin in the case of a PDF/image/HTML file/text file/etc).)
Adam Brenecki