2010-03-17 19 views
7

Estoy tratando de descargar un archivo CSV usando HttpResponse para asegurarme de que el navegador lo trate como un archivo adjunto. Sigo las instrucciones provistas en el here pero mi navegador no muestra un cuadro de diálogo "Guardar como". No puedo entender qué está mal con mi función. Toda la ayuda es apreciada.Descargando un archivo csv en django

 
    dev savefile(request): 
     try: 
      myfile = request.GET['filename'] 
      filepath = settings.MEDIA_ROOT + 'results/' 
      destpath = os.path.join(filepath, myfile) 
      response = HttpResponse(FileWrapper(file(destpath)), mimetype='text/csv') 
      response['Content-Disposition'] = 'attachment; filename="%s"' %(myfile) 
      return response 
     except Exception, err: 
      errmsg = "%s"%(err) 
      return HttpResponse(errmsg) 

Happy Pat's day!

Respuesta

1

Gracias a todos por sus sugerencias. Escogí algunos trucos nuevos :) Sin embargo, creo que encontré la respuesta a mi problema aquí: Downloading CSV via AJAX Mi función "guardar archivo" se llama a través de una solicitud Ajax y parece que ajax tiene una limitación donde "guardar como cuadro de diálogo "no aparece sin importar cuáles son 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!

5

¿Intentó especificar el tipo de contenido? p.

response['Content-Type'] = 'application/x-download'; 

Editar:

Nota, este código desencadena con éxito un "Guardar como" de diálogo para mí. Nota Especifico "application/x-download" directamente en el argumento mimetype. También es posible que desee volver a verificar su código, y asegurarse de que su ruta de 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 
+0

lo probé, todavía no funciona. Puedo ver la respuesta y los encabezados en FireBug pero no obtengo un cuadro de diálogo. – spyder

+0

Prueba mi edición actual. – Cerin

+0

Lo intenté pero no funcionó. Por favor, mira mi respuesta, descubrí que el problema no tiene nada que ver con django. Gracias – spyder

7

Si el archivo es estática (es decir, no genera específicamente para esta solicitud) que no debería estar sirviendo a través de Django de todos modos. Debería configurar alguna ruta (como/static /) para que sea servida por su servidor web, y guardar toda la sobrecarga de django.

Si el archivo es dinámica, hay 2 opciones:

  1. crearlo en la memoria y se sirve de Django.
  2. Créelo en el disco y devuélvalo HttpResponseRedirect para que su servidor web se encargue de la descarga (si el archivo es muy grande, debe usar esta opción).

En cuanto a servir de forma dinámica, 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, sólo tiene que utilizar CSVResponse retorno (...) hacer pasar en una lista de listas, una lista de dicts (con las mismas claves), un QuerySet, un ValuesQuerySet

+0

Se genera sobre la marcha para "esta" solicitud y se almacena temporalmente en/static /. – spyder

+0

Editado después de su comentario –

+0

Gracias por los detalles ! – spyder

0

¿Hay alguna diferencia si no encierra el nombre del archivo entre comillas dobles? El código de ejemplo no cita el nombre del archivo:

response['Content-Disposition'] = 'attachment; filename=foo.xls' 

pero su código hace:

response['Content-Disposition'] = 'attachment; filename="foo.xls"' 
+0

Gracias, lo probé ... no hay alegría. – spyder

0

Thomas, había usado una función Ajax para guardar y descargar este archivo.Parece que, en tal caso, el cuadro "Guardar como" no aparecerá independientemente de los encabezados. Simplemente usé javascript para descargar ese archivo. window.open ("ruta/a/archivo"); y hace el truco. Probé en IE6 y Firefox y aparece el cuadro de diálogo.