From a3a1fcddc5f5292e53b919e11ed656f1c53b46a8 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Fri, 11 Nov 2005 14:51:33 +0000 Subject: [PATCH 1/5] Added docs/outputting_csv.txt git-svn-id: http://code.djangoproject.com/svn/django/trunk@1170 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/outputting_csv.txt | 118 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 docs/outputting_csv.txt diff --git a/docs/outputting_csv.txt b/docs/outputting_csv.txt new file mode 100644 index 0000000000..d8d5a9508e --- /dev/null +++ b/docs/outputting_csv.txt @@ -0,0 +1,118 @@ +========================== +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://www.python.org/doc/current/lib/module-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 ``HttpResponse`` objects are file-like objects. + +.. admonition:: Note + + For more information on ``HttpResponse`` objects, see + `Request and response objects`_. + + For more information on the CSV library, see the `CSV library docs`. + + .. _Request and response objects: http://www.djangoproject.com/documentation/request_response/ + .. _CSV library docs: http://www.python.org/doc/current/lib/module-csv.html + +Here's an example:: + + import csv + from django.utils.httpwrappers 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 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 would 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 ``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. + +Using the template system +========================= + +Alternatively, you can use the Django template system to generate CSV. This +is lower-level than using the convenient CSV, 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 ``{% for %}`` loop. + +Here's an example, which generates the same CSV file as above:: + + from django.utils.httpwrappers import HttpResponse + from django.core.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') + 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``, with this template code:: + + {% 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 `addslashes template filter`_ to ensure +there aren't any problems with quotes. If you can be certain your data doesn't +have single or double quotes in it, you can remove the ``addslashes`` filters. + +.. _addslashes template filter: http://www.djangoproject.com/documentation/templates/#addslashes From 16a3822460455a87a539423b16a6e3990404fd6d Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Fri, 11 Nov 2005 14:53:15 +0000 Subject: [PATCH 2/5] Fixed ReST missing link in docs/outputting_csv.txt git-svn-id: http://code.djangoproject.com/svn/django/trunk@1171 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/outputting_csv.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/outputting_csv.txt b/docs/outputting_csv.txt index d8d5a9508e..4a9459bbd9 100644 --- a/docs/outputting_csv.txt +++ b/docs/outputting_csv.txt @@ -22,7 +22,7 @@ and Django's ``HttpResponse`` objects are file-like objects. For more information on ``HttpResponse`` objects, see `Request and response objects`_. - For more information on the CSV library, see the `CSV library docs`. + For more information on the CSV library, see the `CSV library docs`_. .. _Request and response objects: http://www.djangoproject.com/documentation/request_response/ .. _CSV library docs: http://www.python.org/doc/current/lib/module-csv.html From c62b427b122030cb18df96b1f1017b7aa4b97641 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Fri, 11 Nov 2005 14:54:27 +0000 Subject: [PATCH 3/5] Added a link to docs/outputting_csv.txt git-svn-id: http://code.djangoproject.com/svn/django/trunk@1172 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/outputting_csv.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/outputting_csv.txt b/docs/outputting_csv.txt index 4a9459bbd9..3f95b3600d 100644 --- a/docs/outputting_csv.txt +++ b/docs/outputting_csv.txt @@ -70,7 +70,7 @@ mention: Using the template system ========================= -Alternatively, you can use the Django template system to generate CSV. This +Alternatively, you can use the `Django template system`_ to generate CSV. This is lower-level than using the convenient CSV, but the solution is presented here for completeness. @@ -115,4 +115,5 @@ a line of CSV for each row. It uses the `addslashes template filter`_ to ensure there aren't any problems with quotes. If you can be certain your data doesn't have single or double quotes in it, you can remove the ``addslashes`` filters. +.. _Django template system: http://www.djangoproject.com/documentation/templates/ .. _addslashes template filter: http://www.djangoproject.com/documentation/templates/#addslashes From cb222e4d4e5f3ebe4ba6773c8e39bc5702f4af57 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Fri, 11 Nov 2005 16:42:41 +0000 Subject: [PATCH 4/5] Changed django-admin.py to display help if invoked with no arguments. Thanks, sopel git-svn-id: http://code.djangoproject.com/svn/django/trunk@1173 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/bin/django-admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django/bin/django-admin.py b/django/bin/django-admin.py index 89297d4cf9..c66d195ae5 100755 --- a/django/bin/django-admin.py +++ b/django/bin/django-admin.py @@ -77,7 +77,7 @@ def main(): try: action = args[0] except IndexError: - print_error("An action is required.", sys.argv[0]) + parser.print_usage_and_exit() if not ACTION_MAPPING.has_key(action): print_error("Your action, %r, was invalid." % action, sys.argv[0]) if action in ('createsuperuser', 'init', 'validate'): From 632b63ad76efafff2f602de9c5a4464faa37d51b Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Fri, 11 Nov 2005 17:15:24 +0000 Subject: [PATCH 5/5] Fixed #766 -- Custom methods in admin.list_display can now have an allow_tags attribute, which doesn't strip tags in the methods' output. Thanks, plisk git-svn-id: http://code.djangoproject.com/svn/django/trunk@1174 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/admin/views/main.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 726ffa5eb2..81c494b03f 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -388,10 +388,16 @@ def change_list(request, app_label, module_name): except meta.FieldDoesNotExist: # For non-field list_display values, the value is a method # name. Execute the method. + func = getattr(result, field_name) try: - result_repr = strip_tags(str(getattr(result, field_name)())) + result_repr = str(func()) except ObjectDoesNotExist: result_repr = EMPTY_CHANGELIST_VALUE + else: + # Strip HTML tags in the resulting text, except if the + # function has an "allow_tags" attribute set to True. + if not getattr(func, 'allow_tags', False): + result_repr = strip_tags(result_repr) else: field_val = getattr(result, f.attname) # Foreign-key fields are special: Use the repr of the