Posteriormente a mirar en varios repositorios y páginas de internet al terminar descubrimos la solución que te enseñaremos a continuación.
Solución:
Si el archivo es static (es decir, no generado específicamente para esta solicitud) de todos modos, no debería servirlo a través de django. Debe configurar alguna ruta (como /static/) para ser atendido por su servidor web, y ahorre toda la sobrecarga de django.
Si el archivo es dinámicahay 2 opciones:
- Créalo en memoria y sírvelo desde Django.
- Créelo en el disco y devuélvale un HttpResponseRedirect, para que su servidor web se ocupe de la descarga (si el archivo es muy grande, debe usar esta opción).
En cuanto a servirlo dinámicamente, he estado usando el siguiente código (que es una versión simplificada de ExcelResponse)
import StringIO
from django.db.models.query import ValuesQuerySet, QuerySet
class CSVResponse(HttpResponse):
def __init__(self, data, output_name='data', headers=None, encoding='utf8'):
# Make sure we've got the right type of data to work with
valid_data = False
if isinstance(data, ValuesQuerySet):
data = list(data)
elif isinstance(data, QuerySet):
data = list(data.values())
if hasattr(data, '__getitem__'):
if isinstance(data[0], dict):
if headers is None:
headers = data[0].keys()
data = [[row[col] for col in headers] for row in data]
data.insert(0, headers)
if hasattr(data[0], '__getitem__'):
valid_data = True
assert valid_data is True, "CSVResponse requires a sequence of sequences"
output = StringIO.StringIO()
for row in data:
out_row = []
for value in row:
if not isinstance(value, basestring):
value = unicode(value)
value = value.encode(encoding)
out_row.append(value.replace('"', '""'))
output.write('"%s"n' %
'","'.join(out_row))
mimetype = 'text/csv'
file_ext = 'csv'
output.seek(0)
super(CSVResponse, self).__init__(content=output.getvalue(),
mimetype=mimetype)
self['Content-Disposition'] = 'attachment;filename="%s.%s"' %
(output_name.replace('"', '"'), file_ext)
Para usarlo, simplemente use return CSVResponse(…) pasando una lista de listas, una lista de dictados (con el mismo keys), un QuerySet, un ValuesQuerySet
¿Intentaste especificar el tipo de contenido? p.ej
response['Content-Type'] = 'application/x-download';
Editar:
Tenga en cuenta que este código activa con éxito un cuadro de diálogo “Guardar como”. Tenga en cuenta que especifico “aplicación/descarga x” directamente en el argumento tipo mime. También es posible que desee volver a verificar su código y asegurarse de que la ruta de su archivo sea correcta y que FileWrapper() no esté haciendo algo extraño.
def save_file(request):
data = open(os.path.join(settings.PROJECT_PATH,'data/table.csv'),'r').read()
resp = django.http.HttpResponse(data, mimetype='application/x-download')
resp['Content-Disposition'] = 'attachment;filename=table.csv'
return resp
Gracias a todos por vuestras sugerencias. Escogí algunos trucos nuevos 🙂 Sin embargo, creo que he encontrado la respuesta a mi problema aquí: Descargar CSV a través de AJAX Mi función “guardar archivo” se llama a través de una solicitud de Ajax y parece que ajax tiene una limitación donde “guardar como cuadro de diálogo ” no aparece sin importar cuáles sean los encabezados HTTP.
Debería haber mencionado que uso Ajax para llamar a esta función, pero nunca se me ocurrió que esto podría ser un problema 🙂 ¡Gracias StackOverflow!