I am currently trying to create a function within a Django app to download a pandas dataframe as an image. I wanted to create the image as a temporary file, download it, then delete it. Does anyone know how to integrate tempfile into this code?
Views.py
def download_png(request, study):
Names(study) #Funciton to get (name) variable
Retrieve(study) #Function to get (data) variable
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
pngfilename = str(name) + "_" + str(current_time) + ".png"
temp = tempfile.NamedTemporaryFile(suffix=".png")
fig = temp.write(df2img.plot_dataframe(data))
filepath = temp.name
response = HttpResponse(df2img.save_dataframe(fig=fig, filename=filepath), content_type=mimetypes.guess_type(filepath))
response['Content-Disposition'] = "attachment; filename=%s" % pngfilename
return response
Update 06/30/22:
I had a lot of difficulty integrating the tempfile module because it requires data to be converted to bytes-like objects. Instead I simply resolved on deleting the file after creating it.
def download_png(request, study):
Names(study)
Retrieve(study)
pngfilename = str(name) + "_" + str(current_time) + ".png"
mime_type, _ = mimetypes.guess_type(pngfilename)
fig = df2img.plot_dataframe(data)
df2img.save_dataframe(fig=fig, filename=pngfilename)
response = FileResponse(open(pngfilename, 'rb'), content_type=mime_type)
response['Content-Disposition'] = "attachment; filename=%s" % pngfilename
os.remove(pngfilename)
return response
This is how you can use the tempfile library:
tempfile = tempfile.mktemp(suffix='.png')
with open(temp, 'w') as f:
f.write(df2img.plot_dataframe(data))
do_something_with_your_file(temp)
os.unlink(temp)
Edit: was just reading the tempfile documentation and apparently tempfile.mktemp is prone to race conditions, so you should either use tempfile.mkstemp like:
fd, tempf = tempfile.mkstemp()
Or there is a context manager:
with tempfile.NamedTemporaryFile() as tmp:
with open(tmp.name, 'w') as f:
f.write('some data')
# do something with your tempfile file
And then it will automatically delete the tempfile afterwards.
Related
I am currently working on a Django app that allows me to download an image while only storing the image as a temporary file. My Django app is running on a server while I am accessing the website through a local windows machine. While I am able to download the image, the file will not open. For example, Windows Photos says that "It appears we don't support this file format". Is there something wrong with the code that would cause this problem?
Views.py
def download_png(request, study):
Names(study) #Function to retrieve (name) variable
Retrieve(study) #Function to retrieve (data) variable
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
pngfilename = str(name) + "_" + str(current_time) + ".png"
filepath = BASE_DIR + '/polls/graphics/' + pngfilename
temp, filepath = tempfile.mkstemp(suffix='.png')
with open(temp, 'w') as f:
f = df2img.plot_dataframe(data)
df2img.save_dataframe(fig=f, filename=filepath)
response = HttpResponse(temp, content_type=mimetypes.guess_type(filepath))
response['Content-Disposition'] = "attachment; filename=%s" % pngfilename
return response
Update 06/30/22:
Thank you for all the help. It turns out it is better to use FileResponse rather than HttpResponse when downloading a file Here's what the updated code looks like:
def download_png(request, study):
Names(study)
Retrieve(study)
pngfilename = str(name) + "_" + str(current_time) + ".png"
mime_type, _ = mimetypes.guess_type(pngfilename)
fig = df2img.plot_dataframe(data)
df2img.save_dataframe(fig=fig, filename=pngfilename)
response = FileResponse(open(pngfilename, 'rb'), content_type=mime_type)
response['Content-Disposition'] = "attachment; filename=%s" % pngfilename
os.remove(pngfilename)
return response
In a python script, I have a list of strings where each string in the list will represent a text file. How would I convert this list of strings to a zip archive of files?
For example:
list = ['file one content \nblah \nblah', 'file two content \nblah \nblah']
I have tried variations of the following so far
import zipfile
from io import BytesIO
from datetime import datetime
from django.http import HttpResponse
def converting_strings_to_zip():
list = ['file one content \nblah \nblah', 'file two content \nblah \nblah']
mem_file = BytesIO()
with zipfile.ZipFile(mem_file, "w") as zip_file:
for i in range(2):
current_time = datetime.now().strftime("%G-%m-%d")
file_name = 'some_file' + str(current_time) + '(' + str(i) + ')' + '.txt'
zip_file.writestr(file_name, str.encode(list[i]))
zip_file.close()
current_time = datetime.now().strftime("%G-%m-%d")
response = HttpResponse(mem_file, content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename="'str(current_time) + '.zip"'
return response
But just leads to 0kb zip files
Was able to solve it by swapping a couple of lines (not resorting to saving the lists as files, then zipping files on the hard drive of the server, then loading the zip into memory and piping to the client like current answers suggest).
import zipfile
from io import BytesIO
from datetime import datetime
from django.http import HttpResponse
def converting_strings_to_zip():
list = ['file one content \nblah \nblah', 'file two content \nblah \nblah']
mem_file = BytesIO()
zip_file = zipfile.ZipFile(mem_file, 'w', zipfile.ZIP_DEFLATED)
for i in range(2):
current_time = datetime.now().strftime("%G-%m-%d")
file_name = 'some_file' + str(current_time) + '(' + str(i) + ')' + '.txt'
zip_file.writestr(file_name, str.encode(list[i]))
zip_file.close()
current_time = datetime.now().strftime("%G-%m-%d")
response = HttpResponse(mem_file.getvalue(), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename="'str(current_time) + '.zip"'
return response
You could simply write each of the string into it's own file inside a folder you mkdir and then zip it with the zipfile library or by using shutil which is part of python standard library.
Once you have written the string into a directory of your choice you can do:
import shutil
shutil.make_archive('strings_archive.zip', 'zip', 'folder_to_zip')
reference.
I'm going to create a zip file from some of the image files stored on my server.
I've used the following function to do this:
def create_zip_file(user, examination):
from lms.models import StudentAnswer
f = BytesIO()
zip = zipfile.ZipFile(f, 'w')
this_student_answer = StudentAnswer.objects.filter(student_id=user.id, exam=examination)
for answer in this_student_answer:
if answer.answer_file:
answer_file_full_path = answer.answer_file.path
fdir, fname = os.path.split(answer_file_full_path)
zip.writestr(fname, answer_file_full_path)
zip.close() # Close
zip_file_name = "student-answers_"+ str(examination.id)+"_" + str(user.id) + "_" + date=datetime.datetime.now().strftime("%Y-%m-%d-%H-%M") + '.zip'
response = HttpResponse(f.getvalue(), content_type="application/x-zip-compressed")
response['Content-Disposition'] = 'attachment; filename=%s' % zip_file_name
return response
Everything is fine and all photos are made in zip file but there is only one problem.
The problem is that the photos won't open and this error will appear in Windows:
Its look like we don't support this file format.
What is wrong with my codes?
To append data from file you have to use
write(filename)
Using writestr(filename) you add only string from variable filename but not from file.
I am currently using the code below to generate a word document and then serve this on the web using cherrypy.
tpl.get_docx().save(iostream)
cherrypy.response.headers['Content-Type'] = (
'application/vnd.openxmlformats-officedocument'
'.wordprocessingml.document'
)
cherrypy.response.headers['Content-Disposition'] = (
'attachment; filename={fname}.docx'.format(
fname='SP' + kwargs['sp'] + '-'+ kwargs['WO'] + ' ' + kwargs['site'] + ' - ' + 'RPC Report' +'.docx'
)
)
iostream.seek(0)
return file_generator(iostream)
I plan to create more documents, then zip them in-memory and then serve them on the web. how could this be implmented, i have tried using the zipfile library, it seems complicated zipping in-memory files.
the following example i google around may solve my issue, but not sure how to use it.
import zipfile
import StringIO
zipped_file = StringIO.StringIO()
with zipfile.ZipFile(zipped_file, 'w') as zip:
for i, file in enumerate(files):
file.seek(0)
zip.writestr("{}.csv".format(i), file.read())
zipped_file.seek(0)
After hours of persistance, i got this working, yeahhhh
iostream = BytesIO()
tpl.get_docx().save(iostream)
iostream1 = BytesIO()
tpl1.get_docx().save(iostream1)
zip_output = StringIO.StringIO()
file = zipfile.ZipFile(zip_output, "w")
file.writestr("test.docx", iostream.getvalue())
file.writestr("test1.docx", iostream1.getvalue())
file.close()
cherrypy.response.headers['Content-Type'] = 'application/zip'
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="test.zip"'
return zip_output.getvalue()
I'm trying to rotate and save the image to GCS with the below code.
img = images.Image(blob_key=image.blob)
img.rotate(270)
t = img.execute_transforms(output_encoding=images.PNG)
filename = '/' + UploadHandler.get_gs_bucket_for_images() + 'blobstore_demo.png'
with gcs.open(filename, 'w') as f:
f.write(t)
blobstore_filename = '/gs' + filename
key = blobstore.create_gs_key(blobstore_filename)
But when I try to view the file using GAE's blostore Viewer, I get an encoded image. That is, the content-type for that blob is not set to image/png. So how I managed to set the content-type?
You can define your image mimetype, just edit yor code this way:
img = images.Image(blob_key=image.blob)
img.rotate(270)
t = img.execute_transforms(output_encoding=images.PNG)
filename = '/' + UploadHandler.get_gs_bucket_for_images() + 'blobstore_demo.png'
mimetype = 'image/png'
with gcs.open(filename,'w', content_type=mimetype) as f:
f.write(t)
blobstore_filename = '/gs' + filename
key = blobstore.create_gs_key(blobstore_filename)