1 ==========================
2 Outputting CSV with Django
3 ==========================
5 This document explains how to output CSV (Comma Separated Values) dynamically
6 using Django views. To do this, you can either use the Python CSV library or the
7 Django template system.
9 Using the Python CSV library
10 ============================
12 Python comes with a CSV library, :mod:`csv`. The key to using it with Django is
13 that the :mod:`csv` module's CSV-creation capability acts on file-like objects,
14 and Django's :class:`~django.http.HttpResponse` objects are file-like objects.
19 from django.http import HttpResponse
21 def some_view(request):
22 # Create the HttpResponse object with the appropriate CSV header.
23 response = HttpResponse(mimetype='text/csv')
24 response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
26 writer = csv.writer(response)
27 writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
28 writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
32 The code and comments should be self-explanatory, but a few things deserve a
35 * The response gets a special MIME type, :mimetype:`text/csv`. This tells
36 browsers that the document is a CSV file, rather than an HTML file. If
37 you leave this off, browsers will probably interpret the output as HTML,
38 which will result in ugly, scary gobbledygook in the browser window.
40 * The response gets an additional ``Content-Disposition`` header, which
41 contains the name of the CSV file. This filename is arbitrary; call it
42 whatever you want. It'll be used by browsers in the "Save as..."
45 * Hooking into the CSV-generation API is easy: Just pass ``response`` as the
46 first argument to ``csv.writer``. The ``csv.writer`` function expects a
47 file-like object, and :class:`~django.http.HttpResponse` objects fit the
50 * For each row in your CSV file, call ``writer.writerow``, passing it an
51 iterable object such as a list or tuple.
53 * The CSV module takes care of quoting for you, so you don't have to worry
54 about escaping strings with quotes or commas in them. Just pass
55 ``writerow()`` your raw strings, and it'll do the right thing.
60 Python's :mod:`csv` module does not support Unicode input. Since Django uses
61 Unicode internally this means strings read from sources such as
62 :class:`~django.http.HttpRequest` are potentially problematic. There are a few
63 options for handling this:
65 * Manually encode all Unicode objects to a compatible encoding.
67 * Use the ``UnicodeWriter`` class provided in the `csv module's examples
70 * Use the `python-unicodecsv module`_, which aims to be a drop-in
71 replacement for :mod:`csv` that gracefully handles Unicode.
73 For more information, see the Python documentation of the :mod:`csv` module.
75 .. _`csv module's examples section`: http://docs.python.org/library/csv.html#examples
76 .. _`python-unicodecsv module`: https://github.com/jdunck/python-unicodecsv
78 Using the template system
79 =========================
81 Alternatively, you can use the :doc:`Django template system </topics/templates>`
82 to generate CSV. This is lower-level than using the convenient Python :mod:`csv`
83 module, but the solution is presented here for completeness.
85 The idea here is to pass a list of items to your template, and have the
86 template output the commas in a :ttag:`for` loop.
88 Here's an example, which generates the same CSV file as above::
90 from django.http import HttpResponse
91 from django.template import loader, Context
93 def some_view(request):
94 # Create the HttpResponse object with the appropriate CSV header.
95 response = HttpResponse(mimetype='text/csv')
96 response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
98 # The data is hard-coded here, but you could load it from a database or
101 ('First row', 'Foo', 'Bar', 'Baz'),
102 ('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
105 t = loader.get_template('my_template_name.txt')
109 response.write(t.render(c))
112 The only difference between this example and the previous example is that this
113 one uses template loading instead of the CSV module. The rest of the code --
114 such as the ``mimetype='text/csv'`` -- is the same.
116 Then, create the template ``my_template_name.txt``, with this template code:
118 .. code-block:: html+django
120 {% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
123 This template is quite basic. It just iterates over the given data and displays
124 a line of CSV for each row. It uses the :tfilter:`addslashes` template filter to
125 ensure there aren't any problems with quotes.
127 Other text-based formats
128 ========================
130 Notice that there isn't very much specific to CSV here -- just the specific
131 output format. You can use either of these techniques to output any text-based
132 format you can dream of. You can also use a similar technique to generate
133 arbitrary binary data; see :doc:`/howto/outputting-pdf` for an example.