1👍
csvwriter
can write to any object with a write()
method, according to the docs. The usual Python class to use when you want an in-memory filelike object is a StringIO
instance, or cStringIO
if you’re sure you won’t be writing Unicode objects to it. So your export_to_csv
function should look something like:
import cStringIO
def export_as_csv(report, fields, force_fields):
# define field_names as above, assuming your indentation is correct
csv_buffer = cStringIO.StringIO()
writer = csv.writer(csv_buffer, delimiter=',', quoting=csv.QUOTE_ALL)
field_names = list(field_names) # loses order, but at least it's consistent
writer.writerow(field_names)
row = []
for field in field_names:
row.append(getattr(report, field).encode('utf-8'))
writer.writerow(row)
return csv_buffer
Then something like:
mail.attach("report.csv", export_as_csv(report, fields=list_display, force_fields=True).getvalue() , "text/csv")
Key differences are:
1) csv_buffer
is an in-memory filelike object. Nothing is written to the file system.
2) This handles field lookup for the simple model fields 'primary_id', 'created_date', 'report_size'
that you show in your example code. If you actually need to handle the names of callables in yourfield_names
sequence, it gets harder.
3) This uses a single variable to hold the field_names
after converting to a list. It will probably work to use list(field_names)
and for field in field_names
while field_names
is a set, Python sets and dictionaries should be order-stable as long as no modifications are made, but I find it clearer and more reliable to be explicit about making sure the order syncs up.
4) This returns the cStringIO.StringIO
object rather than the writer. The writer’s work is done once you’ve written everything you want to to it. The cStringIO
object, conversely, should return the buffered CSV contents when you call getvalue()
on it.