theamateurdataanalyst February 2016

Adding zip file from a response to Django FileField

Currently I am making a call to an API an that sends back a zip file. When using requests

res = requests.post('http://url/to/api', files={'file_pro': *my_file*})

I am able to get a successful response with the returned zip as a string. When I examine the contents of my res.contents I get :

PK\x03\x04\x14\x00\x00\x00\x08\x00\x0c\x83HH\xba\xd2\xf1\t\xa1\x00\x00\x00\x04\x01\x00\x00....05\x06\x00\x00\x00\x00\x08\x00\x08\x00\x1e\x02\x00\x00$\x04\x00\x00\x00\x00

It looks like its returning the zip file as a string. I looked at this question here to attempt to transform this string into the original zip file. Specifically I wrote:

my_file = UploadedFile(file=File(zipfile.ZipFile(StringIO.StringIO(res.content)),'r'))
my_file.save()

Upon trying to save I get the following error:

KeyError: 'There is no item named 65536 in the archive'

My ultimate goal is to bind this zip file to an UploadedFile

class UploadedFile(BaseModel):
  file = models.FileField(upload_to='/path', max_length=255)

If I use a html form to reach this API my browser automatically downloads the zip after the request is successful. Any idea how to fix this?

Answers


Derek Kwok February 2016

The requests library allows you get the response back as binary data - http://docs.python-requests.org/en/master/user/quickstart/#binary-response-content.

You don't need to use ZipFile to reconstruct the zip, the data passed back should already be the bytes of a zip file.

from django.core.files.uploadedfile import SimpleUploadedFile

# res.content is the bytes of your API response
res = request.post('http://url/to/api', files={'file_pro': *myfile*})
my_file = SimpleUploadedFile('temp.zip', res.content)

# verify the zip file
assert zipfile.is_zipfile(my_file)

# finally save the file
uploaded_file = UploadedFile(file=my_file)
uploaded_file.save()

# play around with the zipfile
with zipfile.ZipFile(uploaded_file.file) as my_zip_file:
    print(my_zip_file.infolist())

Note that zipfile.ZipFile takes either a filename or a file-like object. In your question, you passed a string/bytes directly into it.

Also consider renaming the UploadedFile model, as Django already has one built-in at django.core.files.uploadedfile.UploadedFile.

Post Status

Asked in February 2016
Viewed 1,104 times
Voted 14
Answered 1 times

Search




Leave an answer