2005-11-11 22:51:33 +08:00
|
|
|
==========================
|
|
|
|
Outputting CSV with Django
|
|
|
|
==========================
|
|
|
|
|
|
|
|
This document explains how to output CSV (Comma Separated Values) dynamically
|
2011-09-05 05:17:30 +08:00
|
|
|
using Django views. To do this, you can either use the Python CSV library or the
|
|
|
|
Django template system.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
Using the Python CSV library
|
|
|
|
============================
|
|
|
|
|
2011-09-05 05:17:30 +08:00
|
|
|
Python comes with a CSV library, :mod:`csv`. The key to using it with Django is
|
|
|
|
that the :mod:`csv` module's CSV-creation capability acts on file-like objects,
|
|
|
|
and Django's :class:`~django.http.HttpResponse` objects are file-like objects.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
Here's an example::
|
|
|
|
|
|
|
|
import csv
|
2006-05-02 09:31:56 +08:00
|
|
|
from django.http import HttpResponse
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
def some_view(request):
|
|
|
|
# Create the HttpResponse object with the appropriate CSV header.
|
2013-01-31 20:39:29 +08:00
|
|
|
response = HttpResponse(content_type='text/csv')
|
2020-07-14 19:32:24 +08:00
|
|
|
response.headers['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
writer = csv.writer(response)
|
|
|
|
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
|
|
|
|
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
The code and comments should be self-explanatory, but a few things deserve a
|
|
|
|
mention:
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
* The response gets a special MIME type, :mimetype:`text/csv`. This tells
|
|
|
|
browsers that the document is a CSV file, rather than an HTML file. If
|
|
|
|
you leave this off, browsers will probably interpret the output as HTML,
|
|
|
|
which will result in ugly, scary gobbledygook in the browser window.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
* The response gets an additional ``Content-Disposition`` header, which
|
|
|
|
contains the name of the CSV file. This filename is arbitrary; call it
|
2015-08-02 05:56:04 +08:00
|
|
|
whatever you want. It'll be used by browsers in the "Save as..." dialog, etc.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
2019-06-17 22:54:55 +08:00
|
|
|
* You can hook into the CSV-generation API by passing ``response`` as the first
|
|
|
|
argument to ``csv.writer``. The ``csv.writer`` function expects a file-like
|
|
|
|
object, and :class:`~django.http.HttpResponse` objects fit the bill.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
* For each row in your CSV file, call ``writer.writerow``, passing it an
|
2019-05-17 23:27:19 +08:00
|
|
|
:term:`iterable`.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
* The CSV module takes care of quoting for you, so you don't have to worry
|
2019-06-17 22:54:55 +08:00
|
|
|
about escaping strings with quotes or commas in them. Pass ``writerow()``
|
|
|
|
your raw strings, and it'll do the right thing.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
2014-03-05 06:40:44 +08:00
|
|
|
.. _streaming-csv-files:
|
|
|
|
|
|
|
|
Streaming large CSV files
|
2016-01-03 18:56:22 +08:00
|
|
|
-------------------------
|
2014-03-05 06:40:44 +08:00
|
|
|
|
|
|
|
When dealing with views that generate very large responses, you might want to
|
|
|
|
consider using Django's :class:`~django.http.StreamingHttpResponse` instead.
|
|
|
|
For example, by streaming a file that takes a long time to generate you can
|
|
|
|
avoid a load balancer dropping a connection that might have otherwise timed out
|
|
|
|
while the server was generating the response.
|
|
|
|
|
|
|
|
In this example, we make full use of Python generators to efficiently handle
|
|
|
|
the assembly and transmission of a large CSV file::
|
|
|
|
|
|
|
|
import csv
|
|
|
|
|
|
|
|
from django.http import StreamingHttpResponse
|
|
|
|
|
2017-06-26 22:30:31 +08:00
|
|
|
class Echo:
|
2014-03-05 06:40:44 +08:00
|
|
|
"""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 some_streaming_csv_view(request):
|
|
|
|
"""A view that streams a large CSV file."""
|
|
|
|
# Generate a sequence of rows. The range is based on the maximum number of
|
|
|
|
# rows that can be handled by a single sheet in most spreadsheet
|
|
|
|
# applications.
|
2014-11-27 08:41:27 +08:00
|
|
|
rows = (["Row {}".format(idx), str(idx)] for idx in range(65536))
|
2014-03-05 06:40:44 +08:00
|
|
|
pseudo_buffer = Echo()
|
|
|
|
writer = csv.writer(pseudo_buffer)
|
|
|
|
response = StreamingHttpResponse((writer.writerow(row) for row in rows),
|
|
|
|
content_type="text/csv")
|
2020-07-14 19:32:24 +08:00
|
|
|
response.headers['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
|
2014-03-05 06:40:44 +08:00
|
|
|
return response
|
|
|
|
|
2005-11-11 22:51:33 +08:00
|
|
|
Using the template system
|
|
|
|
=========================
|
|
|
|
|
2010-08-20 03:27:44 +08:00
|
|
|
Alternatively, you can use the :doc:`Django template system </topics/templates>`
|
2011-09-05 05:17:30 +08:00
|
|
|
to generate CSV. This is lower-level than using the convenient Python :mod:`csv`
|
2010-11-29 14:24:14 +08:00
|
|
|
module, but the solution is presented here for completeness.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
The idea here is to pass a list of items to your template, and have the
|
2008-08-24 06:25:40 +08:00
|
|
|
template output the commas in a :ttag:`for` loop.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
Here's an example, which generates the same CSV file as above::
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
from django.http import HttpResponse
|
2019-10-25 14:11:11 +08:00
|
|
|
from django.template import loader
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
def some_view(request):
|
|
|
|
# Create the HttpResponse object with the appropriate CSV header.
|
2013-01-31 20:39:29 +08:00
|
|
|
response = HttpResponse(content_type='text/csv')
|
2020-07-14 19:32:24 +08:00
|
|
|
response.headers['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
# The data is hard-coded here, but you could load it from a database or
|
|
|
|
# some other source.
|
|
|
|
csv_data = (
|
|
|
|
('First row', 'Foo', 'Bar', 'Baz'),
|
|
|
|
('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
|
|
|
|
)
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
t = loader.get_template('my_template_name.txt')
|
2019-10-25 14:11:11 +08:00
|
|
|
c = {'data': csv_data}
|
2005-11-11 22:51:33 +08:00
|
|
|
response.write(t.render(c))
|
|
|
|
return response
|
|
|
|
|
|
|
|
The only difference between this example and the previous example is that this
|
|
|
|
one uses template loading instead of the CSV module. The rest of the code --
|
2013-01-31 20:39:29 +08:00
|
|
|
such as the ``content_type='text/csv'`` -- is the same.
|
2005-11-11 22:51:33 +08:00
|
|
|
|
2008-08-24 06:25:40 +08:00
|
|
|
Then, create the template ``my_template_name.txt``, with this template code:
|
|
|
|
|
|
|
|
.. code-block:: html+django
|
2005-11-11 22:51:33 +08:00
|
|
|
|
|
|
|
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
|
|
|
|
{% endfor %}
|
|
|
|
|
2019-06-17 22:54:55 +08:00
|
|
|
This short template iterates over the given data and displays a line of CSV for
|
|
|
|
each row. It uses the :tfilter:`addslashes` template filter to ensure there
|
|
|
|
aren't any problems with quotes.
|
2008-08-24 06:25:40 +08:00
|
|
|
|
|
|
|
Other text-based formats
|
|
|
|
========================
|
2005-11-11 22:51:33 +08:00
|
|
|
|
2008-08-24 06:25:40 +08:00
|
|
|
Notice that there isn't very much specific to CSV here -- just the specific
|
|
|
|
output format. You can use either of these techniques to output any text-based
|
|
|
|
format you can dream of. You can also use a similar technique to generate
|
2010-08-20 03:27:44 +08:00
|
|
|
arbitrary binary data; see :doc:`/howto/outputting-pdf` for an example.
|