Streaming a generated CSV with Flask
According to this answer how do I clear a stringio object? it is quicker to just create a new StringIO
object for each line in the file than the method I use below. However if you still don't want to create new StringIO
instances you can achieve what you want like this:
import csvimport StringIOfrom flask import Responsedef iter_csv(data): line = StringIO.StringIO() writer = csv.writer(line) for csv_line in data: writer.writerow(csv_line) line.seek(0) yield line.read() line.truncate(0) line.seek(0) # required for Python 3def csv_response(data): response = Response(iter_csv(data), mimetype='text/csv') response.headers['Content-Disposition'] = 'attachment; filename=data.csv' return response
If you just want to stream back the results as they are created by csv.writer
you can create a custom object implementing an interface the writer expects.
import csvfrom flask import Responseclass Line(object): def __init__(self): self._line = None def write(self, line): self._line = line def read(self): return self._linedef iter_csv(data): line = Line() writer = csv.writer(line) for csv_line in data: writer.writerow(csv_line) yield line.read()def csv_response(data): response = Response(iter_csv(data), mimetype='text/csv') response.headers['Content-Disposition'] = 'attachment; filename=data.csv' return response
If you are dealing with large amounts of data that you don't want to store in memory then you could use SpooledTemporaryFile. This would use StringIO until it reaches a max_size
after that it will roll over to disk.
However, I would stick with the recommended answer if you just want to stream back the results as they are created.