CSV es un formato de datos sencillo que suele ser usada por programas de hojas de cálculo. Básicamente es una serie de filas en una tabla, cada celda en la fila está separada por comas (CSV significa comma-separated values). Por ejemplo, aquí tienes una lista de pasajeros "problemáticos" en líneas aéreas en formato CSV:
Year,Unruly Airline Passengers 1995,146 1996,184 1997,235 1998,200 1999,226 2000,251 2001,299 2002,273 2003,281 2004,304 2005,203
Nota El listado precedente contiene números reales; cortesía de la Administración Federal de Aviación (FAA) de E.E.U.U. Vea http://www.faa.gov/data_statistics/passengers_cargo/unruly_passengers/.
Aunque CSV parezca simple, no es un formato que ha sido definido formalmente.
Diferentes programas producen y consumen diferentes variantes de CSV,
haciendo un poco complicado usarlo. Afortunadamente, Python incluye una
librería estándar para CSV, csv
, que es bastante robusta.
Debido a que el módulo csv
opera sobre objetos similares a ficheros, es muy
fácil usar un HttpResponse
en lugar de un fichero:
import csv
from django.http import HttpResponse
# Número de pasajeros problematicos por año entre 1995 - 2005.
# En una aplicación real esto vendría desde una base de datos o cualquier
# otro medio de almacenamiento.
UNRULY_PASSENGERS = [146,184,235,200,226,251,299,273,281,304,203]
def unruly_passengers_csv(request):
# Creamos el objeto Httpresponse con la cabecera CSV apropiada.
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=unruly.csv'
# Creamos un escritor CSV usando a HttpResponse como "fichero"
writer = csv.writer(response)
writer.writerow(['Year', 'Unruly Airline Passengers'])
for (year, num) in zip(range(1995, 2006), UNRULY_PASSENGERS):
writer.writerow([year, num])
return response
El código y los comentarios deberían ser bastante claros, pero hay unas pocas cosas que merecen mención especial:
- Se le da a la respuesta el tipo MIME
text/csv
(en lugar del tipo predeterminadotext/html
). Esto le dice a los navegadores que el documento es un fichero CSV. - La respuesta obtiene una cabecera
Content-Disposition
adicional, la cual contiene el nombre del fichero CSV. Esta cabecera (bueno, la parte "adjunta") le indicará al navegador que solicite la ubicación donde guardará el fichero (en lugar de simplemente mostrarlo). El nombre de fichero es arbitrario; llámalo como quieras. Será usado por los navegadores en el cuadro de diálogo "Guardar como..." - Usar el API de generación de CSV es sencillo: basta pasar
response
como primer argumento acsv.writer
. La funcióncsv.writer
espera un objeto de tipo fichero, y los de tipoHttpResponse
se ajustan. - Por cada fila en el fichero CSV, invocamos a
writer.writerow
, pasándole un objeto iterable como una lista o una tupla. - El módulo CSV se encarga de poner comillas por ti, así que no tendrás que
preocuparte por escapar caracteres en las cadenas que tengan comillas o
comas en su interior. Limítate a pasar la información a
writerow()
, que hará lo correcto.
Este es el patrón general que usarás siempre que necesites retornar contenido
no HTML: crear un objeto HttpResponse
de respuesta (con un tipo MIME
especial), pasárselo a algo que espera un fichero, y luego devolver la
respuesta.
Veamos unos cuántos ejemplos más.