Class-based view and mixins for responding with CSV in Django. django-separated supports Django 1.3+.
$ pip install django-separated
A ListView that returns a CsvResponse.
You can specify the data for each row using the columns attribute.
columns should be an iterable of 2-tuples where the first index is
an accessor to get the value off of an object and the second is a column
header.
class UserCsvView(CsvView):
model = User
columns = [
('first_name', 'First name'),
('last_name', 'Last name'),
('email', 'Email'),
]
The accessor can be a string or a callable. If it isn't a callable, it will be passed into attrgetter to turn into a callable. If the accessor returns a callable, it will be called. All of the following are valid examples of accessors:
first_namefirst_name.upperget_absolute_urllambda x: x.upvotes.count() - x.downvotes.count()
There is a corresponding get_columns method if you need to have
more dynamic behavior.
The header index is optional, if you want a header to be generated from the
accessor, you can write a simpler columns declaration:
class UserCsvView(CsvView):
model = User
columns = [
'first_name',
'last_name',
'email',
]
Additionally, you can specify the filename of the CSV file that will be
downloaded. It will default to the model name + _list.csv if you don't
provide one. For example:
class UserCsvView(CsvView):
model = User
will have a filename of user_list.csv. But you can override it by
settings the filename attribute. There is a corresponding
get_filename that you can override for more complicated behavior.
By default, CsvView will output the headers as the first line. If you
want to suppress this behavior, set output_headers to False.
A MultipleObjectMixin subclass that returns a CsvResponse.
This is useful in instances where you want to substitute BaseListView for a
ListView of your own. CsvResponseMixin supports all the behavior
mentioned in CsvView, the only machinery you need to hook it up is a
View class that calls render_to_response with a context that has a
queryset available in the object_list key.
class MyWeirdBaseListView(View):
def get(self, request, *args, **kwargs):
return self.render_to_response({
'object_list': User.objects.all(),
})
class MyWeirdCsvView(CsvResponseMixin, MyWeirdBaseListView):
pass
A subclass of HttpResponse that will download as CSV. CsvResponse
requires a filename as the first argument of the constructor.
You can use django-separated in the admin center to export CSV from the admin site.
from separated.admin import CsvExportModelAdmin
class NewsAdmin(CsvExportModelAdmin):
csv_export_columns = [
'title',
'pub_date',
'author.full_name',
]
This adds an action to the change list.
csv_export_columns corresponds to the CsvView.columns attribute. If
you want more fine-grained control, you can override csv_export_view_class
instead:
from datetime import datetime
from separated.admin import CsvExportModelAdmin
from separated.views import CsvView
class NewsCsvView(CsvView):
columns = [
'title',
'pub_date',
'author.full_name',
]
output_headers = False
def get_filename(self, model):
return '%s-news-export.csv' % datetime.today().strftime('Y-m-d')
class NewsAdmin(CsvExportModelAdmin):
csv_export_view_class = NewsCsvView
csv_export_columns and csv_export_view_class also exist as methods
(get_csv_export_columns and get_csv_export_view_class respectively) if
you need change them based on request.
from separated.admin import CsvExportModelAdmin
class NewsAdmin(CsvExportModelAdmin):
staff_export_columns = (
'title',
'pub_date',
'author.full_name',
)
superuser_export_columns = staff_export_columns + (
'secret_column',
)
def get_csv_export_columns(self, request):
if request.user.is_superuser:
return self.superuser_export_columns
else:
return self.staff_export_columns
django-separated provides a couple of helpers for normalizing the data that
comes off of the model before sending it to the CSV writer. These are all
based on a Getter class which handles the different types of accessors.
If you have a boolean value that you wish to be transformed into Yes or
No, you can use the BooleanGetter:
from separated.utils import BooleanGetter
class UserCsvView(CsvView):
model = User
columns = [
BooleanGetter('is_admin'),
]
If you have a model field that has choices and you want the human readable
display to appear in the CSV, you can use the DisplayGetter:
from separated.utils import BooleanGetter
class User(models.Model):
favorite_color = models.CharField(max_length=255,
choices=(
('blue', 'Blue'),
('green', 'Green'),
('red', 'Red'),
))
class UserCsvView(CsvView):
model = User
columns = [
DisplayGetter('favorite_color'),
]
This will end up using the get_favorite_color_display method that Django
automatically adds.