This snippets is inspired from #2995 but add the following:
- get rid of
singledispatch
so we can use it with python2 without pip installing anything - streaming capabilities
- the configuration params (header, fields, exclude...) are passed to the action function so we don't pollute the ModelAdmin class
- fix utf8 issue in header
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import csv
from collections import OrderedDict
from django.db.models import FieldDoesNotExist
from django.http import StreamingHttpResponse
def prep_field(obj, field):
"""
(for export_as_csv action)
Returns the field as a unicode string. If the field is a callable, it
attempts to call it first, without arguments.
"""
if '__' in field:
bits = field.split('__')
field = bits.pop()
for bit in bits:
obj = getattr(obj, bit, None)
if obj is None:
return ""
attr = getattr(obj, field)
output = attr() if callable(attr) else attr
return unicode(output).encode('utf-8') if output is not None else ""
class Echo(object):
"""An object that implements just the write method of the file-like
interface.
"""
def write(self, value):
"""Write the value by returning it, instead of storing in a buffer."""
return value
def export_as_csv(description, fields=None, exclude=None, use_verbose_names=True, include_header=True):
def _export_as_csv(modeladmin, request, queryset):
"""
Usage:
class ExampleModelAdmin(admin.ModelAdmin):
list_display = ('field1', 'field2', 'field3',)
actions = [
export_as_csv(
'export to csv',
fields=['field1', '('foreign_key1__foreign_key2__name', 'label2'),],
include_header=True
)
]
"""
opts = modeladmin.model._meta
def field_name(field):
if use_verbose_names:
return unicode(field.verbose_name).capitalize()
else:
return field.name
# field_names is a map of {field lookup path: field label}
if exclude:
field_names = OrderedDict(
(f.name, field_name(f)) for f in opts.fields if f not in exclude
)
elif fields:
field_names = OrderedDict()
for spec in fields:
if isinstance(spec, (list, tuple)):
field_names[spec[0]] = spec[1]
else:
try:
f, _, _, _ = opts.get_field_by_name(spec)
except FieldDoesNotExist:
field_names[spec] = spec
else:
field_names[spec] = field_name(f)
else:
field_names = OrderedDict(
(f.name, field_name(f)) for f in opts.fields
)
pseudo_buffer = Echo()
writer = csv.writer(pseudo_buffer)
def content_iterator():
if include_header:
yield [i.encode('utf8') for i in field_names.values()]
for obj in queryset.iterator():
yield [prep_field(obj, field) for field in field_names.keys()]
response = StreamingHttpResponse(
(writer.writerow(line) for line in content_iterator()),
content_type='text/csv'
)
response['Content-Disposition'] = 'attachment; filename=%s.csv' % (unicode(opts).replace('.', '_'))
return response
_export_as_csv.short_description = description
return _export_as_csv
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.