@login_required
def sendfile(request, id):
project_file = get_object_or_404(ProjectFile, id=id)
if not (request.user.is_staff or request.user in
project_file.project.members.all()):
return HttpResponseForbidden('No. Sorry.')
response = HttpResponse()
response['X-Sendfile'] = os.path.join(settings.MEDIA_ROOT,
project_file.file)
content_type, encoding =
mimetypes.guess_type(project_file.get_file_url())
if not content_type:
content_type = 'application/octet-stream'
response['Content-Type'] = content_type
response['Content-Length'] = project_file.get_file_size()
response['Content-Disposition'] = 'attachment; filename="%s"' %
os.path.basename(project_file.get_file_url())
return response
You get the idea.
The Apache config denies access to the upload subdirectory altogether;
mod_xsendfile overrides that when it sees the X-Sendfile header in the
response from the Django view. You get to use Django for the complex
authorization, then it lets Apache handle the grunt work of shipping
the file. Pretty nice; I thought this might have been the requirement
that finally pushed me over to nginx or lighty, but not yet....
John
> I installed mod_xsendfile and I tried your code, but the file that's
> downloaded from the view is empty.
> This might be because I've tested it using the development server on
> port 8080. So I guess Apache is out of the loop :/
Yes, this approach only works for requests that go through Apache. I
could have been clearer on how mod_xsendfile works, I guess. The
request is handled just like any Django request. The response from
Django is empty, as you saw; after authorization the view just sets
the X-Sendfile header, which is what tells mod_xsendfile to take over
the response handling and deliver the file. So without Apache and
mod_xsendfile in the loop, you just get that empty response.
You could have Apache add a request header or some other indicator
that the view could check, so it could handle the file itself in your
development environment. Or you could just run under Apache instead of
the dev server.
> I also have Apache running in parallel. Is there any way to have
> Apache send the file after the view (executed via dev server:8080)
> returns the response? Or is there any way around that issue?
No simple way springs to mind.
John