Write CSV with Django
Content Index
- What is a CSV file and why does Django handle it so well
- Advantages of the CSV format for databases
- Preparing your files before working with CSV in Django
- How to correctly convert an Excel file to CSV
- Validating headers, separators, encoding, and newline
- Typical errors when receiving files from clients
- How to import CSV into Django models step by step
- Structuring your model for a clean import
- Using csv.reader and DictReader
- Saving records with objects.create() and get_or_create()
- Data validation: dates, decimals, and empty fields
- Importing CSV from a Django view (practical example)
- Uploading a CSV file from a form
- How to export data to CSV in Django
- Frequently Asked Questions about CSV in Django
Working with CSV files in Django can be as simple as using a csv.reader... or as frustrating as receiving a completely broken Excel file from a client. Over time, I've had to export client data directly from the database and also had to deal with that awful Excel file we've all suffered from at some point. So, in this article, I'm going to explain everything you need to know to handle CSV in Django without losing your patience.
What is a CSV file and why does Django handle it so well
CSV (Comma Separated Values) is one of the simplest and most useful formats for representing tabular data. Django interacts wonderfully with it because:
- It is plain text
- It works perfectly with Python and the csv module
- It is lightweight, fast, and requires no external dependencies
Advantages of the CSV format for databases
- Easy to generate from Django.
- Perfect for bulk record import.
- Compatible with any system: Excel, Google Sheets, databases, ERPs.
Preparing your files before working with CSV in Django
How to correctly convert an Excel file to CSV
The conversion seems simple: open in Excel → Save as CSV.
But in practice, you must consider:
- UTF-8 encoding
- Correct separator (comma or semicolon)
- Cleaning of empty rows
- Making sure data is ordered and ready for processing.
- Handling large files
- Use StreamingHttpResponse if the file exceeds thousands of records.
- Avoiding duplicates and ensuring integrity
- get_or_create() is your best ally.
- Recommended encoding to prevent errors
- UTF-8 without BOM → the safe option.
Validating headers, separators, encoding, and newline
Before importing a CSV into Django, check:
- That columns have clear names without strange spaces
- That separators are homogeneous
- That the file uses the correct newline (`newline=""`)
- That there are no broken tildes or phantom characters
Typical errors when receiving files from clients
When I received that impossible Excel file, I discovered errors like:
- Mixed columns
- Repeated headers
- Dates with various formats
- Rows with "invisible" values
How to import CSV into Django models step by step
Structuring your model for a clean import
A typical model might look like this:
class Cliente(models.Model):
nombre = models.CharField(max_length=150)
email = models.EmailField()
fecha_registro = models.DateField()Using csv.reader and DictReader
- csv.reader: works with lists
- csv.DictReader: works with dictionaries using CSV headers
Saving records with objects.create() and get_or_create()
Example:
with open("clientes.csv") as file:
reader = csv.DictReader(file)
for row in reader:
Cliente.objects.get_or_create(
email=row["email"],
defaults={
"nombre": row["nombre"],
"fecha_registro": row["fecha_registro"]
}
)Data validation: dates, decimals, and empty fields
When I processed real client data, I encountered dates like 12/1/23, 2023-01-12, and even "enero 2023" (January 2023).
My rule: normalize before saving.
Importing CSV from a Django view (practical example)
Uploading a CSV file from a form
A straightforward way:
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="archivo">
<button type="submit">Importar</button>
</form>Processing rows and handling errors
def importar_csv(request):
if request.method == "POST":
archivo = request.FILES["archivo"]
data = archivo.read().decode("utf-8").splitlines()
reader = csv.reader(data)
next(reader) # saltar encabezados
for fila in reader:
Cliente.objects.create(
nombre=fila[0],
email=fila[1],
fecha_registro=fila[2]
)
return render(request, "importar.html")How to export data to CSV in Django
For example, I had to export client data to send personalized reports. And right after that, I had to take a completely messy Excel file from the client, convert it to CSV, and process it from Django. CSV is that tool that always gets you out of trouble.
To write files, the same scheme as the previous codes is used, but the files must be opened in write mode and the writer() function must be used instead of the reader() function; it is also important to note that the file to be written does not have to exist (in the following example, to avoid deleting the previous file, the file to be referenced is called "Libro2"):
def csv_write(request):
filename="documents/Libro2.csv"
try:
file = open(filename, 'w', newline="")
#print(type(file))
csv_writer = csv.writer(file, delimiter=",")
# print(type(csv_writer))
csv_writer.writerow(["Movie 1","Movie 2", "Movie 3"])
csv_writer.writerow(["Avengers","Batman", "Superman"])
csv_writer.writerow(["Avengers 3","Batman 2", "Other"])
csv_writer.writerow(["Avengers 4","Batman", "Spiderman"])
file.close()
except (IOError) as error:
print("Error {}".format(error))
return render(request, 'csv.html')When in write mode, a structure must be presented that we want to replicate in the file; in this case, it would be lists, which, as we saw in the reading examples, are the formats returned when reading the files.
To write a list, the writerow() function is used; you can also use writerows() to write multiple lists:
data=[
["Name","Surname","Age"],
["Jon","Snow",33],
["Daenerys","Targaryen",25],
["Tyrion","Lannister",40],
["Jaime","Lannister",35],
["Cersei","Lannister",36]
]
writer.writerows(data)The newline option is also used as an empty string; this prevents a space from being placed between records when a new column is written; without defining newline:
Movie 1;Movie 2;Movie 3
Avengers;Batman;Superman
Avengers 3;Batman 2;Other
Definiendo el newline:
Pelicula 1;Pelicula 2;Pelicula 3
Avengers;Batman;Superman
Avengers 3;Batman 2;Otro
Su ruta:
csvs\urls.py
urlpatterns = [
// ***
path(csv_write, views.csv_write),And we will have an output file with the format we specified earlier:
documents\Libro2.csv
Pelicula 1;Pelicula 2;Pelicula 3
Avengers;Batman;Superman
Avengers 3;Batman 2;Otro
Avengers 4;Batman;SpidermanAnother example:
def exportar_clientes(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=clientes.csv'
writer = csv.writer(response)
writer.writerow(["nombre", "email", "fecha_registro"])
for cliente in Cliente.objects.all():
writer.writerow([cliente.nombre, cliente.email, cliente.fecha_registro])
return responseExporting CSV from the admin panel (with a reusable mixin)
It is also possible to implement this type of functionality from Django Admin:
class ExportCsvMixin:
def export_as_csv(self, request, queryset):
meta = self.model._meta
field_names = [field.name for field in meta.fields]
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = f'attachment; filename={meta}.csv'
writer = csv.writer(response)
writer.writerow(field_names)
for obj in queryset:
writer.writerow([getattr(obj, field) for field in field_names])
return responseAdding it to the admin:
@admin.register(Cliente)
class ClienteAdmin(admin.ModelAdmin, ExportCsvMixin):
actions = ["export_as_csv"]When generating files from Django, always remember:
writer = csv.writer(response, lineterminator="\n")
Frequently Asked Questions about CSV in Django
- How to debug encoding errors?
- Try `archivo.read().decode("utf-8", errors="ignore")`.
- What to do if the CSV has too many columns?
- Map only the necessary ones with an intermediate dictionary.
- How to process large CSV files without blocking the server?
- Use asynchronous tasks (Celery or RQ).
I agree to receive announcements of interest about this Blog.
We will see how to write and read CSV files using Django and a native Python module, several examples and recommendations for its use.