1

So, my problem I suppose is quite easy, but I have ... some issue with it :)

So in my application written in Django I invoke creating Excel file using Ajax like this :

            $.ajax({
                url: '/ajax-send-xls-desktop/',
                type: 'POST',
                contentType: "application/vnd.ms-excel",
                data: JSON.stringify(data_xls),
                dataType: 'text',
                success: function(result) {
                    window.open('data:application/vnd.ms-excel,' + result);
                }
            });

In my backend I create Excel file and return response like this one :

        response = HttpResponse(mimetype="application/vnd.ms-excel")
        response['Content-Disposition'] = 'attachment; filename=opispozycji.xls'
        response['Content-Type'] = 'application/vnd.ms-excel; charset=utf-8'
        book.save(response)

Everything I received is a lot of characters :

    N*8X"��1���Arial1���Arial1���Arial1���Arial1���Arial1���Arial1���Arial1���Arial
�General���� �� ���� �� ���� �� ���� �� ���� �� ���� �� ���� �� ���� �� ���� �� ���� ��
���� �� ���� �� ���� �� ���� �� ���� �� ���� �� �� �� �� �� �� �� ���`��Opis pozycji��
PDane wygnerowane przez Interzam - Internetowa Platforma Zarzdzania Zam�wieniamiSIDCPV

Can anyone confirm that the problem lies in charset encoding ?

ndpu
  • 22,225
  • 6
  • 54
  • 69
Lukasz Ciesluk
  • 718
  • 1
  • 17
  • 29
  • Can you save the stream to disk and validate that you have a correct Excel file? – Joe Jan 16 '14 at 10:16
  • Yes i can save stream to disk, but I do know why I must on my own add .xls extension to file despite of specify correct mimetype. When I open Excel file, it's content in some part is quite good (which I would like to receive) but there is a lot of signs that it should be there... – Lukasz Ciesluk Jan 16 '14 at 10:22

3 Answers3

0

This works for me:

response = HttpResponse(mimetype="application/ms-excel")
response['Content-Disposition'] = "attachment; filename=%s" % "excel.xls"
book.save(response)
return response

i have just link to view url and in result dialog shown. With ajax call it cant be done...

update:

I found a workaround solution (iframe with form used) for case where you need to dynamically request file here - Download a file by jQuery.Ajax. You can use plugin created by @JohnCulviner - http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/ or my little function ajax_download:

// creates iframe and form in it with hidden field,
// then submit form with provided data
// url - form url
// data - data to form field
// input_name - form hidden input name

function ajax_download(url, data, input_name) {
    var $iframe,
        iframe_doc,
        iframe_html;

    if (($iframe = $('#download_iframe')).length === 0) {
        $iframe = $("<iframe id='download_iframe'" +
                    " style='display: none' src='about:blank'></iframe>"
                   ).appendTo("body");
    }

    iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
    if (iframe_doc.document) {
        iframe_doc = iframe_doc.document;
    }

    iframe_html = "<html><head></head><body><form method='POST' action='" +
                  url +"'>" +
                  "<input type=hidden name='" + input_name + "' value='" +
                  JSON.stringify(data) +"'/></form>" +
                  "</body></html>";

    iframe_doc.open();
    iframe_doc.write(iframe_html);
    $(iframe_doc).find('form').submit();
}

in your case (with click event for example):

$('#someid').on('click', function() {
    ajax_download('/ajax-send-xls-desktop/', data_xls, 'data');
});
Community
  • 1
  • 1
ndpu
  • 22,225
  • 6
  • 54
  • 69
0

The Data URI scheme mentions base 64 encoding as an option. The alternative is doing the relevant character encoding. I suggest you base 64 encode the data. Here is a question which will help you do that.

Community
  • 1
  • 1
Joe
  • 46,419
  • 33
  • 155
  • 245
  • are you sure it's possible to use Excel like this? – Joe Jan 16 '14 at 11:54
  • Maybe ;) I use those two tutorials : http://www.jquerybyexample.net/2012/10/export-table-data-to-excel-using-jquery.html and https://djangosnippets.org/snippets/2233/ – Lukasz Ciesluk Jan 16 '14 at 12:50
0

Do you actually need to use Ajax? It seems like it is overcomplicating things.

I have excel downloads in my application, but they are standard Django views. Most of them are class based generic views, where I have overridden the render_to_response method and set the content type with excel.

So I have a standard ListView of my object to generate HTML, and and ExcelListView, which overrides the render to response method, to write an excel rather than passing it to an HTML template.

class ViewToExcel():
    """
    This class will implement the excel writing functionality, by overwriting the render_to_response method
    """
    headings2attrributes = {}  # empty default

    def render_to_response(self, context, **response_kwargs):
        """
        Returns a response with a an excel sheet.
        """
        self.generate_headings()   # specific to my application

        wbk = xlwt.Workbook()
        sheet = wbk.add_sheet('sheet 1')

        # Create the HttpResponse object with the appropriate CSV header.
        response = HttpResponse(mimetype='application/vnd.ms-excel')
        response['Content-Disposition'] = 'attachment; filename=Report.xls'

       row_num = 0
       col_num = 0 

       ## write row of headings
       for hd_att in self.headings2attrributes :
            sheet.write(row_num, col_num , hd_att[0])
            col_num += 1
            row_num += 1

      object_list = self.get_queryset()

    # write rows of data ## again, this is fairly specific to my implementation
    for object  in object_list:   ## go through each object instance in queryset
        self.write_object_row(sheet, row_num, 0 , object)
        row_num += 1
    wbk.save(response)    
    return response



class MyView(ListView):
    """
    This will produce the standard HTML page (which should contain a link to the excel download)
    """
    context_object_name = "my_list"
    template_name = "sequencing/MyView.html"

    def get_queryset(self):
       """
       get your objects and populate a queryset / querydict here
       """
        ...        
        ...
        return MyObjects.all().filter(blah, blah= blah)


class MyExcelView( ViewToExcel , MyView):
    """
    This view will subclass both the ViewToExcel class as well as MyView. 
    When it is called it will reuse the get_queryset method from MyView, but will use RenderToResponse from ViewToExcel - producing excel response, rather than HTML
    The way I have implemented it is that the MyExcelView provides HeadingsToAttributes dictionary, which is used to write the excel. 
    """       
    headings2attrributes_template = [
        ['heading', 'attribbute' ]  , 
        ['heading_2', 'callable' ], 
wobbily_col
  • 11,390
  • 12
  • 62
  • 86
  • Thank you very much for this code but unfortunately this one can not be placed in my project. I must use Ajax. I also found this piece of code (https://bitbucket.org/ljean/django-excel-export/src/11fe78248745f7c9c701cad289484598b4a5f8d2/views.py) which I currently use but it doesn't work ;/ – Lukasz Ciesluk Jan 21 '14 at 10:48