Error sending a file using Django - file turns out empty - django

This is my views.py files:
from django.http import HttpResponse
def render(request):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
response['X-Sendfile'] = '/files/filename.pdf'
# path relative to views.py
return response
When I run the server and request
http://localhost:8080/somestring
I get an empty file called somefilename.pdf. I suspect that there is some crucial part missing in render.
The other parts of this app outside of views.py are correct to my understanding.

Here is the code that solved my problem:
from django.http import HttpResponse
from wsgiref.util import FileWrapper
def render(request):
response = HttpResponse(FileWrapper(open('file.pdf', 'rb')), content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
return response

The manage.py runserver development serer doesn't support X-Sendfile. In production, you need to enable X-Sendfile for your server (e.g. Apache).
You may find the django-sendfile package useful. It has a backend that you can use in development. However, it hasn't had a release in some time, and I found that I had to apply pull request 62 to get Python 3 support.

Related

how to prompt user to save a pdf file to his local machine in django?

I am fairly new to Django and my project requires me to prompt user to open a pdf upon clicking a link. I already have the pdf file on my local machine and dont want to recreate it using Reportlab. Is there any way to do it?
I tried
with open("/user/some/directory/somefilename.pdf") as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
return response
but it returned 404 page not found as the requested url wasn't in the URLconf of myproject.urls
What am I missing?
In general, when user click "Download", you can:
- If file is not existed:
- Generate pdf file use ReportLab as you did.
- Store generated file to a public dir.
return HttpResponseRedirect(file_url_to_public_dir)
The way that worked for me is by using FileSystemStorage
from django.core.files.storage import FileSystemStorage
from django.http import HttpResponse
fs = FileSystemStorage("/Users/location/where/file/is_saved/")
with fs.open("somefile.pdf") as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="my_pdf.pdf"'
return response
and now its prompting the user to save the file as it normally would!

Stream file from remote url to Django view response

Is there any way to stream file from remote URL with Django Response (without downloading the file locally)?
# view.py
def file_recover(request, *args, **kwargs):
file_url = "http://remote-file-storage.com/file/111"
return StreamFileFromURLResponse(file_url)
We have file storage (files can be large - 1 GB and more). We can't share download url (there are security issues). File streaming can significantly
increase download speed by forwarding download stream to Django response.
Django has built in StreamingHttpResponse class which should be given an iterator that yields strings as content. In example below I'm using requests Raw Response Content
import requests
from django.http import StreamingHttpResponse
def strem_file(request, *args, **kwargs):
r = requests.get("http://host.com/file.txt", stream=True)
resp = StreamingHttpResponse(streaming_content=r.raw)
# In case you want to force file download in a browser
# resp['Content-Disposition'] = 'attachment; filename="saving-file-name.txt"'
return resp

django zip file doesn't get downloaded

I want to download zip files using Django views. I have gone through many solutions in stack overflow. But the file does not get downloaded at all. Here is the code I am using.
Could anyone, tell me where I am going wrong.
response = HttpResponse(mimetype='application/zip')
response['Content-Disposition'] = 'attachment; filename=%s' % doc[Zip_file_name]
response['X-Sendfile'] = "./Zipfiles" # the path where the zip files are stored
return response
In chrome, If I use inspect element, and double click on the url shown in the network tab, the file gets downloaded as it is recognized as a http get request, whereas on button click nothing happens.
Please Help.
from django.http import HttpResponse
from django.core.servers.basehttp import FileWrapper
# file
response = HttpResponse(FileWrapper(myfile), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response

Return json file in a view

In a view I create new file with:
sys.stdout = open(backup_name, 'w')
call_command('dumpdata')
How can I now return this file to user?
I tried to change mimetype in HttpResponse to 'application/json' but how can I add file content to response?
Or maybe there is other way to return file?
.
I know it's a bit late, but I found this a useful starting point so I thought others could benefit from what I found too.
For a small file, if you place the json file in a template folder, django can find it and you can return it with render_to_response:
return render_to_response(data_file,mimetype='application/json')
I found this to be problematic for large datasets on certain browsers. I would get the error An existing connection was forcibly closed by the remote host. An alternative approach fixed this.
First you must create full path to your file. Use the PROJECT_ROOT variable (defined by PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) in settings.py). To access this and the os methods you must import settings, os in views.py. Once you have this file location you can return it using the code below:
backup_path = os.path.join(settings.PROJECT_ROOT, "templates", "json_dumps", "large_file.json")
return HttpResponse(open(backup_path, 'r'),content_type = 'application/json; charset=utf8')
I found this worked well for even very large files.
OK I have it:
response = HttpResponse(open(backup_path, "r"), mimetype='application/json', )
response['Content-Disposition'] = "filename=%s" % backup_name"
After saving file on disc I open it for reading and set file name in response.
Anyone has another idea?
I was trying to return a dictionary as a json file. Here is my solution:
import json
import cStringIO as StringIO
from wsgiref.util import FileWrapper
from django.http import HttpResponse
data_string = json.dumps(data)
json_file = StringIO.StringIO()
json_file.write(data_string)
json_file.seek(0)
wrapper = FileWrapper(json_file)
response = HttpResponse(wrapper, content_type='application/json')
response['Content-Disposition'] = 'attachement; filename=dump.json'
return response
Just copy/link/call the dumpdata code related to model serialization, and dump it directly into the response, so you avoid permission problems and filesystem pollution. Content-disposition and mimetype still applies.
Remember anyway that dumpdata can be a lenghty process, so you are exposed to timeouts.
My final solution is (thanks to saverio):
response = HttpResponse(mimetype='application/json', )
response['Content-Disposition'] = "filename=%s" % backup_name
sys.stdout = response
call_command('dumpdata')

How to return static files passing through a view in django?

I need to return css files and js files according to specific logic. Clearly, static serve does not perform what I need. I have a view, whose render method uses logic to find the proper file, but then I have to return it. Technically, I can just read the file and stuff it into a HttpResponse object with the proper mime type, but I was wondering if there was a better strategy. (like fpassthru() in php)
This is what I used:
test_file = open('/home/poop/serve/test.pdf', 'rb')
response = HttpResponse(content=test_file)
response['Content-Type'] = 'application/pdf'
response['Content-Disposition'] = 'attachment; filename="%s.pdf"' \
% 'whatever'
return response
What webserver software are you using?
At least for Apache and NginX, there is a module enabling you to use the X-SendFile HTTP header. The NginX website says Lighty can do this, too.
In your wrapper view:
...
abspath = '/most_secret_directory_on_the_whole_filesystem/protected_filename.css'
response = HttpResponse()
response['X-Sendfile'] = abspath
response['Content-Type'] = 'mimetype/submimetype'
# or let your webserver auto-inject such a header field
# after auto-recognition of mimetype based on filename extension
response['Content-Length'] = <filesize>
# can probably be left out if you don't want to hassle with getting it off disk.
# oh, and:
# if the file is stored via a models.FileField, you just need myfilefield.size
response['Content-Disposition'] = 'attachment; filename=%s.css' \
% 'whatever_public_filename_you_need_it_to_be'
return response
Then you can connect the view via http://mysite.com/url_path/to/serve_hidden_css_file/.
You can use it anytime you need to do something upon a file being requested that should not be directly accessible to users, like limiting who can access it, or counting requests to it for stats, or whatever.
For Apache: http://tn123.ath.cx/mod_xsendfile/
For NginX: http://wiki.nginx.org/NginxXSendfile
Why don't you use Django staticfiles inside your view
from django.contrib.staticfiles.views import serve
...
def view_function(request):
return serve(request, 'absolute_path_to_file_name')
Why not return an HttpResponseRedirect to the location of the correct static file?
Serving files directly from a view is very slow. If you are looking for normal file serving see this question: Having Django serve downloadable files
To very easily serve files through a view (for debug purposes, for example) keep reading.
# In your urls.py:
url(r'^test-files/(?P<name>.+)/$', views.test_files, name='test_files'),
# In your views.py:
from django.http.response import HttpResponse
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt # (Allows file download with POST requests, can be omitted)
def test_files(request, name):
if name == "myxml":
fsock = open("/djangopath/data/static/files/my.xml", "rb")
return HttpResponse(fsock)
This allows you to download the file from: http://127.0.0.1:8080/app/test-files/myxml/
Pass an iterator (such as the result of open()) to the HttpResponse constructor.
you can use below code in your view:
Note:in this function I return images but you can return every thing based your need and set your context_type
from django.http import HttpResponse,Http404
import os
def img_finder(request, img_name):
try:
with open(os.path.dirname(os.path.abspath(__file__)) + '/static/img/' + img_name, 'rb') as f:
return HttpResponse(f.read(), content_type="image/jpeg")
except IOError:
raise Http404
Here the most simple and efficient way to do this.
app/urls.py
from django.urls import re_path
from app import views
urlpatterns = [
re_path(r'^(?P<public_url>.*)$', views.public, name="public"),
]
Warning : put the URL pattern at the end
app/views.py
import os
from django.conf import settings
from django.views.static import serve
def public(request, public_url):
public_folder = os.path.join(str(settings.BASE_DIR), 'folder_path')
return serve(request, public_url, document_root=public_folder)
It should be wasteful to use django to serve static content (not to mention, several orders of magnitude slower).
I'd rather convert the view into a context processor and use the variables in templates to find what blocks to include.