123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- ========================
- How to create CSV output
- ========================
- This document explains how to output CSV (Comma Separated Values) dynamically
- using Django views. To do this, you can either use the Python CSV library or the
- Django template system.
- Using the Python CSV library
- ============================
- 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.
- Here's an example::
- import csv
- from django.http import HttpResponse
- def some_view(request):
- # Create the HttpResponse object with the appropriate CSV header.
- response = HttpResponse(
- content_type="text/csv",
- headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
- )
- 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:
- * 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.
- * The response gets an additional ``Content-Disposition`` header, which
- contains the name of the CSV file. This filename is arbitrary; call it
- whatever you want. It'll be used by browsers in the "Save as..." dialog, etc.
- * 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.
- * For each row in your CSV file, call ``writer.writerow``, passing it an
- :term:`iterable`.
- * The CSV module takes care of quoting for you, so you don't have to worry
- about escaping strings with quotes or commas in them. Pass ``writerow()``
- your raw strings, and it'll do the right thing.
- .. _streaming-csv-files:
- Streaming large CSV files
- -------------------------
- 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
- class Echo:
- """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.
- rows = (["Row {}".format(idx), str(idx)] for idx in range(65536))
- pseudo_buffer = Echo()
- writer = csv.writer(pseudo_buffer)
- return StreamingHttpResponse(
- (writer.writerow(row) for row in rows),
- content_type="text/csv",
- headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
- )
- Using the template system
- =========================
- Alternatively, you can use the :doc:`Django template system </topics/templates>`
- to generate CSV. This is lower-level than using the convenient Python :mod:`csv`
- module, but the solution is presented here for completeness.
- The idea here is to pass a list of items to your template, and have the
- template output the commas in a :ttag:`for` loop.
- Here's an example, which generates the same CSV file as above::
- from django.http import HttpResponse
- from django.template import loader
- def some_view(request):
- # Create the HttpResponse object with the appropriate CSV header.
- response = HttpResponse(
- content_type="text/csv",
- headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
- )
- # 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"),
- )
- t = loader.get_template("my_template_name.txt")
- c = {"data": csv_data}
- 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 --
- such as the ``content_type='text/csv'`` -- is the same.
- Then, create the template ``my_template_name.txt``, with this template code:
- .. code-block:: html+django
- {% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
- {% endfor %}
- 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.
- Other text-based formats
- ========================
- 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
- arbitrary binary data; see :doc:`/howto/outputting-pdf` for an example.
|