Générer du CSV avec Django

Ce document explique comment générer du CSV (Comma Separated Values) dynamiquement en utilisant Django views. Pour cela, vous pouvez soit utiliser la bibliothèque CSV Python, soit utiliser le système de templates de Django.

Utiliser la bibliothèque CSV Python

Python est livré avec une bibliothèque CSV, csv. La clé pour l’utiliser avec Django est que le module csv agit sur des objets équivalents fichiers, et les objets HttpResponse de Django sont des objets équivalents fichiers.

Voici une exemple:

import csv
from django.http import HttpResponse

def some_view(request):
    # Crée un objet HttpResponse avec l'entête CSV adéquat
    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

Le code et commentaires se comprennent d’eux-mêmes, mais quelques petites choses méritent qu’on s’y attarde:

  • La réponse reçoit un type MIME spécial, text/csv. Cela indique au navigateur que le document est un fichier CSV au lieu d’être un fichier HTML. Sans cela, les navigateurs interpréteront sans doute le document comme étant du HTML, ce qui aboutira à l’affichage d’un infâme charabia.
  • La réponse reçoit une entête supplémentaire Content-Disposition, qui contient le nom du fichier CSV. Ce nom de fichier est libre; appelez-le comme vous le voulez. Il sera utilisé par les navigateurs dans le dialogue “Enregistrer sous...”, etc.
  • Hooker l’API CSV-generation est facile: passez simplement response en premier argument à csv.writer. La fonction csv.writer s’attends à un objet de type fichier, et les objets HttpResponse en sont.
  • Pour chaque rangée dans votre fichier CSV, appelez writer.writerow, en lui passant un objet itérable comme une liste ou un tuple.
  • Le module CSV s’occupe des guillemets pour vous, vous n’avez donc pas à vous préoccuper d’échapper les chaînes avec des guillemets ou des virgules. Passez simplement vos chaînes brutes à writerow(), et il fera ce qu’il faut.

Manipuler Unicode

Le module Python csv ne supporte pas les entrées Unicode. Puisque Django utilise Unicode en interne cela veut dire que les chaînes lues depuis des sources comme HttpRequest sont potentiellement problématiques. Il y a quelques solutions pour gérer cela:

Plus plus d’informations, voir la documentation Python du module csv.

Utiliser le système de templates

Vous avez aussi la possibilité d’utiliser le Django template system pour générer du CSV. C’est de plus bas niveau que l’utilisation du module Python csv, cette solution est présentée ici pour être complets.

Ici, l’idée est de passer une liste d’items à votre template, et que le template insère les virgules via une boucle for.

Voici un exemple qui génère le même fichier CSV que précédemment:

from django.http import HttpResponse
from django.template import loader, Context

def some_view(request):
    # Crée l'objet HttpResponse avec l'entête CSV adéquat.
    response = HttpResponse(mimetype='text/csv')
    response['Content-Disposition'] = 'attachment; filename=somefilename.csv'

    # Ici, les données sont codées en dur, mais vous pouvez les récupérer depuis une
    # base de données ou depuis toute autre 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

La seule différence entre cet exemple et le précédent est que celui-ci charge et utilise un template, au lieu du module CSV. Le reste du code – comme le mimetype='text/csv' – est identique.

Ensuite, créez un template my_template_name.txt, avec le code suivant:

{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
{% endfor %}

Ce template est plutôt élémentaire. Il parcourt les données fournies et affiche une ligne CSV pour chaque rangée. Il utilise le filtre de template addslashes pour être sûr qu’il n’y ait pas de problèmes avec les guillemets.

Autres formats texte

Notez qu’il n’y a rien ici qui soit spécifique au CSV – juste le format de sortie adéquat. Vous pouvez utiliser l’une de ces techniques pour sortir tout format texte dont vous rêvez. Vous pouvez également utiliser une technique semblable pour générer des données binaires arbitraires; voir Outputting PDFs with Django pour un exemple.

Contact