# Django 6.0.7 documentation

# Hur man skapar CSV-utdata

Detta dokument förklarar hur man dynamiskt skriver ut CSV (Comma Separated Values) med hjälp av Django-vyer. För att göra detta kan du antingen använda Pythons CSV-bibliotek eller Djangos mallsystem.

## Använda Pythons CSV-bibliotek

Python levereras med ett CSV-bibliotek, `csv`. Nyckeln till att använda det med Django är att `csv`-modulens CSV-skapande kapacitet fungerar på filliknande objekt, och Djangos `HttpResponse`-objekt är filliknande objekt.

Här är ett exempel:

    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

Koden och kommentarerna borde vara självförklarande, men det finns några saker som förtjänar att nämnas:

- Svaret får en speciell MIME-typ, text/csv. Detta talar om för webbläsarna att dokumentet är en CSV-fil, snarare än en HTML-fil. Om du utelämnar detta kommer webbläsarna förmodligen att tolka utdata som HTML, vilket resulterar i ful, skrämmande gobbledygook i webbläsarfönstret.

- Svaret får ytterligare en `Content-Disposition` header, som innehåller namnet på CSV-filen. Detta filnamn är godtyckligt; kalla det vad du vill. Det kommer att användas av webbläsare i dialogrutan ”Spara som…” etc.

- Du kan koppla in dig på CSV-generering API genom att skicka `response` som det första argumentet till `csv.writer`. Funktionen `csv.writer` förväntar sig ett filliknande objekt, och `HttpResponse`-objekt passar bra.

- För varje rad i CSV-filen anropar du `writer.writerow` och ger den en iterable.

- CSV-modulen tar hand om citering åt dig, så du behöver inte oroa dig för att undkomma strängar med citattecken eller kommatecken i dem. Skicka dina råa strängar till `writerow()` så gör den det rätta.

### Streaming av stora CSV-filer

När du hanterar vyer som genererar mycket stora svar kanske du vill överväga att använda Djangos `StreamingHttpResponse` istället. Genom att strömma en fil som tar lång tid att generera kan du till exempel undvika att en lastbalanserare tappar en anslutning som annars skulle ha avbrutits medan servern genererade svaret.

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"'},
        )

## Använda mallsystemet

Alternativt kan du använda Django mallsystem för att generera CSV. Detta är på en lägre nivå än att använda den praktiska Python `csv`-modulen, men lösningen presenteras här för fullständighetens skull.

Tanken här är att skicka en lista med objekt till din mall och låta mallen mata ut kommatecken i en `for`-loop.

Här är ett exempel som genererar samma CSV-fil som ovan:

    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

Den enda skillnaden mellan det här exemplet och det föregående är att det här exemplet använder template loading i stället för CSV-modulen. Resten av koden - till exempel `content_type='text/csv'` - är densamma.

Skapa sedan mallen `my_template_name.txt`, med denna mallkod:

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

Denna korta mall itererar över de angivna data och visar en rad CSV för varje rad. Den använder mallfiltret `addslashes` för att säkerställa att det inte finns några problem med citattecken.

## Andra textbaserade format

Observera att det inte finns så mycket specifikt för CSV här - bara det specifika utdataformatet. Du kan använda någon av dessa tekniker för att mata ut vilket textbaserat format som helst som du kan drömma om. Du kan också använda en liknande teknik för att generera godtyckliga binära data; se Så här skapar du PDF-filer för ett exempel.