# Documentazione Django 6.0.7

# Come creare un output su CSV

Questo documento spiega come fare output di CSV (Comma Separated Values) in modo dinamico usando Django. Per fare ciò, puoi sia usare la libreria CSV di Python che il sistema di template di Django.

## Utilizzando la libreria CSV di Python

Python è dotato di una libreria CSV, `csv`. La chiave dell’usarla con Django è che le capacità di creazione di CSV del modulo `csv` agiscono su oggetti file-like e gli oggetti di Django `HttpResponse` sono oggetti file-like.

Qui un esempio:

    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

Il codice ed i commenti dovrebbero essere auto esplicativi, ma alcuni dettagli meritano un approfondimento:

- La response ottiene un MIME type speciale, text/csv. Questo dice ai browser che il documento è un file CSV, piuttosto che un file HTML. Se non lo specifichi, i browser probabilmente intepreteranno l’output come HTML, che risulterà in un brutto e spaventoso nonsense nella finestra del browser.

- La risposta ottine un header `Content-Disposition` aggiuntivo, che contiene il nome del file CSV. Questo nome è arbitrario; chiamalo come vuoi. Sarà usato dai browser nel dialogo «Salva come…» ecc…

- Puoi agganciarti alla API per la generazione di CSV passando `response` come primo argomento a `csv.writer`. La funzione `csv.writer` si aspetta un oggetto file-like e `HttpResponse` fa al caso suo.

- Per ogni riga del tuo CSV, chiama `writer.writerow`, passando un iterable.

- Il modulo CSV si occupa del quoting per te, quindi non devi preoccuparti di fare escape delle stringhe con quote o virgole. Passa a `writerow()` le tue stringhe grezze e farà la cosa giusta.

### Streaming di grossi file CSV

Quando hai a che fare con view che generano response molto grandi, potresti voler considerare `StreamingHttpResponse` di Django, invece. Per esempio, facendo streaming di un file che ci mette tanto ad essere generato puoi evitare che il load balancer interrompa una connessione che sarebbe andata fuori tempo massimo mentre il server generava la risposta.

In this example, we make full use of Python generators to efficiently handle the assembly and transmission of a large CSV file. Rows are batched together to reduce HTTP overhead and improve compression efficiency when used with `GZipMiddleware`:

    import csv
    from itertools import batched

    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)

        def stream_batched_rows():
            for batch in batched(rows, 100):
                yield "".join(writer.writerow(row) for row in batch)

        return StreamingHttpResponse(
            stream_batched_rows(),
            content_type="text/csv",
            headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
        )

## Utilizzare il template system

Alternativamente, puoi usare il sistema di template di Django per generare CSV. Questo è più low-level rispetto all’utilizzo del conveniente modulo `csv` ma la soluzione viene qui proposta per completezza.

L’idea è di passare una lista di oggetti al tuo template, e lasciare che il template crei le virgole nel ciclo `for`

Qui c’è un esempio, che genera lo stesso file CSV visto in precedenza:

    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 hardcoded 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

La sola differenza tra questo esempio e quello precedente è che questo usa il caricamento del template invece del modulo CSV. Il resto del codice – come `content_type='text/csv'` – è lo stesso.

Quindi, crea il template `my_template_name.txt`, con questo codice:

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

Questo breve template itera i dati e mostra una riga del CSV alla volta. Utilizza il filtro template `addslashes` per essere sicuro che non ci siano problemi con gli apici.

## Altri formati basati sul testo

Nota che non c’è niente di molto specifico di CSV qui – solo il formato di output. Puoi usare entrambe queste tecniche per fare output di qualsiasi file in formato testo che vuoi. Puoi anche utilizzare una tecnica simile per generare dati binari arbitrari; vedi Come creare file PDF per avere un esempio.