views:

314

answers:

2

I have a view that takes data from my site and then makes it into a zip compressed csv file. Here is my working code sans zip:

def backup_to_csv(request):
    response = HttpResponse(mimetype='text/csv')
    response['Content-Disposition'] = 'attachment; filename=backup.csv'

    writer = csv.writer(response, dialect='excel')

    #code for writing csv file go here...

    return response

and it works great. Now I want that file to be compressed before it gets sent out. This is where I get stuck.

def backup_to_csv(request):

    output = StringIO.StringIO() ## temp output file
    writer = csv.writer(output, dialect='excel')

    #code for writing csv file go here...

    response = HttpResponse(mimetype='application/zip')
    response['Content-Disposition'] = 'attachment; filename=backup.csv.zip'

    z = zipfile.ZipFile(response,'w')   ## write zip to response
    z.writestr("filename.csv", output)  ## write csv file to zip

    return response

But thats not it and I have no idea how to do this.

+4  A: 

Note how, in the working case, you return response... and in the NON-working case you return z, which is NOT an HttpResponse of course (while it should be!).

So: use your csv_writer NOT on response but on a temporary file; zip the temporary file; and write THAT zipped bytestream into the response!

Alex Martelli
Ok, I updated my OP to reflect what I think you're saying here. but there is still something I'm missing. I get an AttributeError saying "StringIO has no __len__ method". Should I be using something else other than StringIO for writing the csv to?
nbv4
To extract the string value of a StringIO instance (so you can get its `len` etc etc), use `thestringioinstance.getvalue()` once you're done writing to it (and before you close it!-).
Alex Martelli
+1  A: 

OK I got it. Here is my new function:

def backup_to_csv(request):

    output = StringIO.StringIO() ## temp output file
    writer = csv.writer(output, dialect='excel')

    #code for writing csv file go here...

    response = HttpResponse(mimetype='application/zip')
    response['Content-Disposition'] = 'attachment; filename=backup.csv.zip'

    z = zipfile.ZipFile(response,'w')   ## write zip to response
    z.writestr("filename.csv", output.getvalue())  ## write csv file to zip

    return response
nbv4
Yep, that will work (if the uncompressed output fits nicely in memory, else consider a temporary file on disk).
Alex Martelli