diff -r 5ff1fc726848 -r c6bca38c1cbf parts/django/docs/howto/outputting-csv.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parts/django/docs/howto/outputting-csv.txt Sat Jan 08 11:20:57 2011 +0530 @@ -0,0 +1,137 @@ +========================== +Outputting CSV with Django +========================== + +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. + +.. _Python CSV library: http://docs.python.org/library/csv.html + +Using the Python CSV library +============================ + +Python comes with a CSV library, ``csv``. The key to using it with Django is +that the ``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(mimetype='text/csv') + response['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, ``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..." + dialogue, etc. + + * Hooking into the CSV-generation API is easy: Just pass ``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 + iterable object such as a list or tuple. + + * 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. Just pass + ``writerow()`` your raw strings, and it'll do the right thing. + +Handling Unicode +~~~~~~~~~~~~~~~~ + +Python's ``csv`` module does not support Unicode input. Since Django uses +Unicode internally this means strings read from sources such as +:class:`~django.http.HttpRequest` are potentially problematic. There are a few +options for handling this: + + * Manually encode all Unicode objects to a compatible encoding. + + * Use the ``UnicodeWriter`` class provided in the `csv module's examples + section`_. + + * Use the `python-unicodecsv module`_, which aims to be a drop-in + replacement for ``csv`` that gracefully handles Unicode. + +For more information, see the Python `CSV File Reading and Writing`_ +documentation. + +.. _`csv module's examples section`: http://docs.python.org/library/csv.html#examples +.. _`python-unicodecsv module`: https://github.com/jdunck/python-unicodecsv +.. _`CSV File Reading and Writing`: http://docs.python.org/library/csv.html + +Using the template system +========================= + +Alternatively, you can use the :doc:`Django template system ` +to generate CSV. This is lower-level than using the convenient Python ``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, Context + + def some_view(request): + # Create the HttpResponse object with the appropriate CSV header. + response = HttpResponse(mimetype='text/csv') + response['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 = Context({ + '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 ``mimetype='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 template is quite basic. It just 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.