Error opening photos stored in zip file in Django - python

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.

Related

Django: Downloaded image won't open

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

Django: Download a temporary image

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.

Zip and server multiple in-memory files

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()

PySide QFTP put only uploading 35-40 bytes

When I use QFTP's put command to upload a file it only uploads around 40 bytes of the specified file. I'm catching the dataProgress signal and I'm getting the progress but the total size of the file is only read to be around 40 bytes. Is there anything wrong with my code, or is it a problem on the FTP server's side?
Here is my upload function:
def upload(self):
filename = QFileDialog.getOpenFileName(self, 'Upload File', '.')
fname = QIODevice(filename[0])
dataname = filename[0]
data = os.path.basename(dataname)
#data = data[data.find("/") + 1:]
print data
print fname
if not self.fileTree.currentItem():
self.qftp.put(fname, data)
elif "." in self.fileTree.currentItem().text(0):
self.qftp.put(fname, self.fileTree.currentItem().parent().text(0) + data)
elif self.fileTree.currentItem().text(0) == "/":
self.qftp.put(fname, data)
else:
return
Alright, figured out what I needed to do. I needed to create a QFile and read all of the bytes from that file and then pass that to the put command.
def upload(self):
filename = QFileDialog.getOpenFileName(self, 'Upload File', '.')
data = QFile(filename[0])
data.open(1)
qdata = QByteArray(data.readAll())
file = os.path.basename(filename[0])
print data
if not self.fileTree.currentItem():
self.qftp.put(qdata, file, self.qftp.TransferType())
elif "." in self.fileTree.currentItem().text(0):
self.qftp.put(qdata, self.fileTree.currentItem().parent().text(0) + file)
elif self.fileTree.currentItem().text(0) == "/":
self.qftp.put(qdata, file)
else:
return
I'm guessing that data = os.path.basename(dataname) means data is always a string containing the name of the file. Try changing this to be an open fileobj by using data = open(os.path.basename(dataname), 'rb')
edit
Looking at PySide.QtNetwork.QFtp.put(data, file[, type=Binary]) and PySide.QtNetwork.QFtp.put(dev, file[, type=Binary]) - the order of arguments is data/dev then file - so it's the wrong way around in your code...

Creating a zip file stream in python with Cherry Py?

I would like to create a zip file on the fly to serve to users through Cherry Py: I tried the following code that produced an invalid zip file:
#cherrypy.expose
def ZipDir(self, *args):
path = "\\".join(args)
output = StringIO.StringIO()
file = zipfile.ZipFile(output, "w")
zip_filename = path + ".zip"
cherrypy.response.headers['Content-Type'] = 'application/zip'
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="%s"' % (zip_filename,)
dir = filter(lambda x: x.lower().endswith(".mp3") or not ("." in x), os.listdir("G:\\Music\\" + path))
for f in dir:
file.write("G:\\Music\\" + path + "\\" + f,f,zipfile.ZIP_DEFLATED)
return output.getvalue()
The file size looks about right, but it doesnt register as a zip file with any acrhicing applications.
I forgot to call file.close() before the return. That fixed it!

Categories

Resources