views:

1305

answers:

5

How to serve users a dynamically generated ZIP archive in Django?

I'm making a site, where users can choose any combination of available books and download them as ZIP archive. I'm worried that generating such archives for each request would slow my server down to a crawl. I have also heard that Django doesn't currently have a good solution for serving dynamically generated files.

+1  A: 

Can't you just write a link to a "zip server" or whatnot? Why does the zip archive itself need to be served from Django? A 90's era CGI script to generate a zip and spit it to stdout is really all that's required here, at least as far as I can see.

Andy Ross
+5  A: 

Django doesn't directly handle the generation of dynamic content (specifically Zip files). That work would be done by Python's standard library. You can take a look at how to dynamically create a Zip file in Python here.

If you're worried about it slowing down your server you can cache the requests if you expect to have many of the same requests. You can use Django's cache framework to help you with that.

Overall, zipping files can be CPU intensive but Django shouldn't be any slower than another Python web framework.

Cristian
+1  A: 

Wouldn't it be simpler to put a download link beside each book instead of a check box so that the visitor can download the books on by one? I fail to see how this would inconvenience the visitor...

Toni Ruža
+13  A: 

The solution is as follows.

Use Python module zipfile to create zip archive, but as the file specify StringIO object (ZipFile constructor requires file-like object). Add files you want to compress. Then in your Django application return the content of StringIO object in HttpResponse with mimetype set to application/x-zip-compressed (or at least application/octet-stream). If you want, you can set content-disposition header, but this should not be really required.

But beware, creating zip archives on each request is bad idea and this may kill your server (not counting timeouts if the archives are large). Performance-wise approach is to cache generated output somewhere in filesystem and regenerate it only if source files have changed. Even better idea is to prepare archives in advance (eg. by cron job) and have your web server serving them as usual statics.

zgoda
StringIO will be gone in Python 3.0, so you may want to bracket your code accordingly.
Jeff Bauer
It's not gone, just moved to the io module. http://docs.python.org/3.0/library/io.html#io.StringIO
Roger Pate
+1  A: 

I suggest to use separate model for storing those temp zip files. You can create zip on-fly, save to model with filefield and finally send url to user.

Advantages:

  • Serving static zip files with django media mechanism (like usual uploads).
  • Ability to cleanup stale zip files by regular cron script execution (which can use date field from zip file model).
dobrych