python 49 lines · 7 steps

Streaming a CSV export in Django

A class-based view streams a large query as CSV without buffering the whole file in memory.

Explained by highlit
1import csv
2 
3from django.http import StreamingHttpResponse
4from django.utils.timezone import now
5from django.views import View
6 
7from .models import Order
8 
9 
10class Echo:
11 def write(self, value):
12 return value
13 
14 
15class OrderExportView(View):
16 columns = [
17 ("id", "Order ID"),
18 ("customer_email", "Customer"),
19 ("total", "Total"),
20 ("status", "Status"),
21 ("created_at", "Created"),
22 ]
23 
24 def get_queryset(self, request):
25 qs = Order.objects.select_related("customer").order_by("created_at")
26 status = request.GET.get("status")
27 if status:
28 qs = qs.filter(status=status)
29 since = request.GET.get("since")
30 if since:
31 qs = qs.filter(created_at__date__gte=since)
32 return qs
33 
34 def rows(self, request):
35 writer = csv.writer(Echo())
36 yield writer.writerow(label for _, label in self.columns)
37 queryset = self.get_queryset(request)
38 for order in queryset.iterator(chunk_size=2000):
39 yield writer.writerow(
40 getattr(order, field) for field, _ in self.columns
41 )
42 
43 def get(self, request, *args, **kwargs):
44 filename = f"orders-{now():%Y%m%d-%H%M%S}.csv"
45 response = StreamingHttpResponse(
46 self.rows(request), content_type="text/csv"
47 )
48 response["Content-Disposition"] = f'attachment; filename="{filename}"'
49 return response
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Streaming responses let you send arbitrarily large exports without holding the full payload in memory.
  2. 2A pseudo-buffer that just returns what it's given lets csv.writer produce strings you can yield one at a time.
  3. 3Pairing an iterator queryset with generator rows keeps both the database and the response streaming in chunks.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Streaming a CSV export in Django — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code