tags:

views:

3521

answers:

3

I'm writing an image bank with Django, and I want to add a button to get a hi-res version of an image (the low-res is shown in the details page). If I put just an <a> link, the browser will open the image instead of downloading it. Adding an HTTP header like:

Content-Disposition: attachment; filename="beach008.jpg"

works, but since it's an static file, I don't want to handle the request with Django. Currently, I'm using NGINX to serve static files, and dynamic pages are redirected via FastCGI to the Django process. I'm thinking about using NGINX add-header command, but could it set the filename="xx" part?. Or maybe there's some way to handle the request in Django, but make NGINX serve the content?

+2  A: 

I wrote a simple decorator, for django.views.static.serve view

Which works for me perfectly.

def serve_download(view_func):
    def _wrapped_view_func(request, *args, **kwargs):
        response = view_func(request, *args, **kwargs)
        response['Content-Type'] = 'application/octet-stream';
        import os.path
        response['Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename(kwargs['path'])
        return response
    return _wrapped_view_func

Also you can play with nginx mime-types

http://wiki.codemongers.com/NginxHttpCoreModule#types

This solution didn't work for me, because I wanted to have both direct link for the file (so user can view images, for example), and download link.

A: 

What i'm doing now is to use a different URL for download than for 'views', and add the filename as an URL arg:

usual media link: http://xx.com/media/images/lores/f_123123.jpg download link: `http://xx.com/downs/hires/f_12323?beach008.jpg

and nginx has a config like this:

    location /downs/ {
        root   /var/www/nginx-attachment;
        add_header Content-Disposition 'attachment; filename="$args"';
    }

but i really don't like the smell of it.

Javier
+6  A: 

If your django app is proxied by nginx you can use x-accell-redirect. You need to pass a special header in your response, nginx will intercepet this and start serving the file, you can also pass Content-Disposition in the same response to force a download.

That solution is good if you want to control which users acess these files.

You can also use a configuration like this:

    #files which need to be forced downloads
    location /static/high_res/ {
        root /project_root;

        #don't ever send $request_filename in your response, it will expose your dir struct, use a quick regex hack to find just the filename
        if ($request_filename ~* ^.*?/([^/]*?)$)
        {
            set $filename $1;
        }

        if ($filename ~* ^.*?\.(jpg)|(png)|(gif)$){
                       add_header Content-Disposition "attachment; filename=$filename";
                   }
         }

    location /static {
        root /project_root;
    }

This will force download on all images in some high_res folder (MEDIAROOT/high_rest). And for the other static files it will behave like normal. Please note that this is a modified quick hack that works for me. It may have security implications, so use it with precaution.

Vasil
great! exactly what i was looking for.
Javier