I try to download img from url, add it to zip archive and then response this archive by Django HttpResponse.
import os
import requests
import zipfile
from django.http import HttpResponse
url = 'http://some.link/img.jpg'
file = requests.get(url)
data = file.content
rf = open('tmp/pic1.jpg', 'wb')
rf.write(data)
rf.close()
zipf = zipfile.ZipFile('tmp/album.zip', 'w') # This file is ok
filename = os.path.basename(os.path.normpath('tmp/pic1.jpg'))
zipf.write('tmp/pic1.jpg', filename)
zipf.close()
resp = HttpResponse(open('tmp/album.zip', 'rb'))
resp['Content-Disposition'] = 'attachment; filename=album.zip'
resp['Content-Type'] = 'application/zip'
return resp # Got corrupted zip file
When I save file to tmp folder - it's ok, I can extract it.
But when I response this file I get 'Error 1/2/21' on MacOS or Unexpected EOF if I try to open in Atom editor (just for test).
I also used StringIO instead of saving zip file, but it doesn't influence the result.
If you're using Python 3, you'd do it like this:
import os, io, zipfile, requests
from django.http import HttpResponse
# Get file
url = 'https://some.link/img.jpg'
response = requests.get(url)
# Get filename from url
filename = os.path.split(url)[1]
# Create zip
buffer = io.BytesIO()
zip_file = zipfile.ZipFile(buffer, 'w')
zip_file.writestr(filename, response.content)
zip_file.close()
# Return zip
response = HttpResponse(buffer.getvalue())
response['Content-Type'] = 'application/x-zip-compressed'
response['Content-Disposition'] = 'attachment; filename=album.zip'
return response
That's without saving the file. Downloaded file goes directly to io.
To response saved file, use this syntax:
response = HttpResponse(open('path/to/file', 'rb').read())
Related
I am trying to perform excel export functionality in Django with xls. But When I am trying to perform that file is not downloading and there is no error also.
Here is my code.
def excelExport(request):
response = HttpResponse(content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment;filename="InitalRegistaration.xls"'
work_book = xlwt.Workbook(encoding='utf-8')
uc = u"".join(chr(0x0410 + i) for i in range(32)) # some Cyrillic characters
u8 = uc.encode("UTF-8")
work_sheet = work_book.add_sheet('Client Registration')
work_sheet.write(0,0,"Clients")
work_book.save(response)
return response
I don't know what's wrong with my code but the file is not getting downloaded nor there is the error coming from the code.
In python3 something like this should work:
from io import BytesIO
from tempfile import NamedTemporaryFile
with NamedTemporaryFile() as tmp:
work_book.save(tmp.name)
content = BytesIO(tmp.read())
response = HttpResponse(content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response['Content-Disposition'] = 'attachment; filename=%s' % dname
return response
I have a button which downloads a excel file with extension .xls. I am using module xlrd to parse the file and return it back to the user. However it appears to add the object name into the excel file instead of the data.
How can I return the file to the user with the data rather than the objects name?
View
def download_file(self, testname):
import csv, socket, os, xlrd
extension = '.xls'
path = r"C:\tests\{}_Report{}".format(testname, extension)
try:
f = xlrd.open_workbook(path)
response = HttpResponse(f, content_type='application/ms-excel')
response['Content-Disposition'] = 'attachment; filename={}_Report{}'.format(testname, extension)
return response
except Exception as Error:
return HttpResponse(Error)
return redirect('emissions_dashboard:overview_view_record')
Excel result
Download successful:
Content:
Note: I understand this is an old file format but is required for this particular project.
You are trying to send a xlrd.book.Book object, not a file.
You used xlrd to do your things in the workbook, and then saved to a file.
workbook = xlrd.open_workbook(path)
#... do something
workbook.save(path)
Now you send it like any other file:
with open(path, 'rb') as f:
response = HttpResponse(f.read(), content_type="application/ms-excel")
response['Content-Disposition'] = 'attachment; filename={}_Report{}'.format(testname, extension)
def download(request):
f = open("next_op.xls")
data = f.read()
f.close()
response = HttpResponse(data, content_type = './application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="nextop.xls"'
return response
When I use this code, I can download the file correctly, but the file name is invalid. I get the file name "download", and I found the response header doesn't include the Content-Disposition after I download the file.
you may need this:
fd = open(file, 'rb')
return FileResponse(fd, as_attachment=True, filename='xxx')
So i am currently creating a text file from a jinja2 template on the fly and having it be downloaded by the users browser, however i want to add an option to send it somewhere via FTP (all the FTP details are predefined and wont change)
how do i create the file to be sent?
Thanks
code:
...
device_config.stream(
STR = hostname,
IP = subnet,
BGPASNO = bgp_as,
LOIP = lo1,
DSLUSER = dsl_user,
DSLPASS = dsl_pass,
Date = install_date,
).dump(config_file)
content = config_file.getvalue()
content_type = 'text/plain'
content_disposition = 'attachment; filename=%s' % (file_name)
response = None
if type == 'FILE':
response = HttpResponse(content, content_type=content_type)
response['Content-Disposition'] = content_disposition
elif type == 'FTP':
with tempfile.NamedTemporaryFile() as temp:
temp.write(content)
temp.seek(0)
filename = temp.name
session = ftplib.FTP('192.168.1.1','test','password')
session.storbinary('STOR {0}'.format(file_name), temp)
session.quit()
temp.flush()
return response
EDIT
needed to add temp.seek(0) before sending the file
You can use the tempfile module to create a named temporary file.
import tempfile
with tempfile.NamedTemporaryFile() as temp:
temp.write(content)
temp.flush()
filename = temp.name
session.storbinary('STOR {0}'.format(file_name), temp)
Here is a working example using BytesIO under io module. Code is tested and works.
import ftplib
import io
session = ftplib.FTP('192.168.1.1','USERNAME','PASSWORD')
# session.set_debuglevel(2)
buf=io.BytesIO()
# b'str' to content of buff.write() as it throws an error in python3.7
buf.write(b"test string")
buf.seek(0)
session.storbinary("STOR testfile.txt",buf)
session.quit()
Is it possible to make a zip archive and offer it to download, but still not save a file to the hard drive?
To trigger a download you need to set Content-Disposition header:
from django.http import HttpResponse
from wsgiref.util import FileWrapper
# generate the file
response = HttpResponse(FileWrapper(myfile.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response
If you don't want the file on disk you need to use StringIO
import cStringIO as StringIO
myfile = StringIO.StringIO()
while not_finished:
# generate chunk
myfile.write(chunk)
Optionally you can set Content-Length header as well:
response['Content-Length'] = myfile.tell()
You'll be happier creating a temporary file. This saves a lot of memory. When you have more than one or two users concurrently, you'll find the memory saving is very, very important.
You can, however, write to a StringIO object.
>>> import zipfile
>>> import StringIO
>>> buffer= StringIO.StringIO()
>>> z= zipfile.ZipFile( buffer, "w" )
>>> z.write( "idletest" )
>>> z.close()
>>> len(buffer.getvalue())
778
The "buffer" object is file-like with a 778 byte ZIP archive.
Why not make a tar file instead? Like so:
def downloadLogs(req, dir):
response = HttpResponse(content_type='application/x-gzip')
response['Content-Disposition'] = 'attachment; filename=download.tar.gz'
tarred = tarfile.open(fileobj=response, mode='w:gz')
tarred.add(dir)
tarred.close()
return response
Yes, you can use the zipfile module, zlib module or other compression modules to create a zip archive in memory. You can make your view write the zip archive to the HttpResponse object that the Django view returns instead of sending a context to a template. Lastly, you'll need to set the mimetype to the appropriate format to tell the browser to treat the response as a file.
models.py
from django.db import models
class PageHeader(models.Model):
image = models.ImageField(upload_to='uploads')
views.py
from django.http import HttpResponse
from StringIO import StringIO
from models import *
import os, mimetypes, urllib
def random_header_image(request):
header = PageHeader.objects.order_by('?')[0]
image = StringIO(file(header.image.path, "rb").read())
mimetype = mimetypes.guess_type(os.path.basename(header.image.name))[0]
return HttpResponse(image.read(), mimetype=mimetype)
def download_zip(request,file_name):
filePath = '<path>/'+file_name
fsock = open(file_name_with_path,"rb")
response = HttpResponse(fsock, content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response
You can replace zip and content type as per your requirement.
Same with in memory tgz archive:
import tarfile
from io import BytesIO
def serve_file(request):
out = BytesIO()
tar = tarfile.open(mode = "w:gz", fileobj = out)
data = 'lala'.encode('utf-8')
file = BytesIO(data)
info = tarfile.TarInfo(name="1.txt")
info.size = len(data)
tar.addfile(tarinfo=info, fileobj=file)
tar.close()
response = HttpResponse(out.getvalue(), content_type='application/tgz')
response['Content-Disposition'] = 'attachment; filename=myfile.tgz'
return response