I've found several messages on this list discussing ways to send large files in a HttpResponse. One can use FileWrapper, or one can use a generator and yield chunks of the large file. What about the case when the large file is generated at HTTP request time? In this case, it would be annoying to have the user wait for the page to generate the large file and then stream the file. Instead we would want a way to start the HTTP response (so that the user gets the download dialogue), generate the large file, and then stream the file. Let's take the following example:
def create_tarball(): > path = create_some_big_tarball() > > chunk = None > fh = open(path, 'r') > while True: > chunk = fh.read(1024 * 128) > if chunk == '': > break > yield chunk > > def sample_view(request): > response = HttpResponse(create_tarball(), > mimetype='application/x-compressed') > response['Content-Disposition'] = "attachment;filename=mytarball.tar.gz" > The above example nearly accomplishes what we want, but it doesn't start the HTTP response before the tarball is created, hence making the user wait a long time before the download dialogue box shows up. Let's try something like this (notice the addition of a noop yield): def create_tarball(): yield '' # noop to send the HTTP headers > path = create_some_big_tarball() > > chunk = None > fh = open(path, 'r') > while True: > chunk = fh.read(1024 * 128) > if chunk == '': > break > yield chunk > > def sample_view(request): > response = HttpResponse(create_tarball(), > mimetype='application/x-compressed') > response['Content-Disposition'] = "attachment;filename=mytarball.tar.gz" > The issue with the above example is that the "yield ''" seems to be ignored. HTTP headers are not sent before the tarball is created. Similarly, "yield ' '" and "yield None" don't work, because they corrupt the tarball (HttpResponse calls str() on the iterable items given to the HttpResponse constructor). As a temporary solution, we're writing an empty gzip file in the first yield. Our large tarball is gzipped, and since gzip files can be concatenated to one and other, our hack seems to be working. In the above example, replace the first "yield ''" with: noop = StringIO.StringIO() > empty = gzip.GzipFile(mode='w', fileobj=noop) > empty.write("") > empty.close() > yield noop.getvalue() > I'm wondering if there is a better way to accomplish this? I don't quite understand why HTTP responses are written to stdout. Possibly orthogonal to that, it seems like, in theory, yielding an empty value in the generator should work, because a flush is called after the HTTP headers are written. Any ideas, either on how to solve this problem with the Django API, or on why Django doesn't send HTTP headers on a "yield ''"? Thanks! Alex --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~----------~----~----~----~------~----~------~--~---