0

I am trying to convert a dictionary to csv and then download the csv file on the fly. When i return the response, I see the rows in the httpresponse. But I want it to download the content into a csv file in my local machine.

def export_csv_from_dict(data):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="accounts.csv"'

    keys = data[0].keys()
    dict_writer = csv.DictWriter(response, keys)
    dict_writer.writeheader()
    dict_writer.writerows(data)

    return response

def accounts_function(request):
    # rows is a list of dictionary [{'name': 'a'}, {'name': 'b'}]
    rows = get_rows_data(matched_accounts)
    return data.export_csv_from_dict(rows)

I have tried many different method I saw on stackoverflow, such as filewrapper, using FileResponse, using writing to a temp file and returning it with filewrapper. Also tried using StringIO. None seems to be doing what I want to happen. Can someone explain what I am doing wrong, please. Thanks.

In chrome debugger, I see the proper content in the desired csv format. It won't pop up the download to computer window/action.

Here is now I am triggering it. Don't think this

    $('#exp_csv').click(function(){
        $.ajax({
            'url': '/targeturl/',
            'type': 'get',
            data: {
                'exp_csv': true,
                'search_string': search
            },
            success: function(response){
                // do something
            },
            error: function(){
                // do something else
            }
        })
    });
rak1n
  • 671
  • 1
  • 8
  • 17
  • Possible duplicate of [Having Django serve downloadable files](http://stackoverflow.com/questions/1156246/having-django-serve-downloadable-files) – Two-Bit Alchemist Jul 11 '16 at 20:33
  • I always accomplished this back when I was using Django by setting mimetype to `application/force-download` like in linked question's answer. – Two-Bit Alchemist Jul 11 '16 at 20:33
  • Can't use mimetype in django anymore, and when I try to set content type to application/force-download, it doesn't force download it. Also I saw some comments about how this is not the best practice, but sort of a hack. – rak1n Jul 11 '16 at 23:09
  • I think it's "sort of a hack" because browsers can handle mimetypes however they like. There's no guarantee that any specific mimetype is going to be presented to the user as a download vs handled by the browser. (Think of the change in browser PDF handling over the years.) Did you look through the other answers on that question? – Two-Bit Alchemist Jul 12 '16 at 13:27
  • yes i went through almost all the response on that answer. – rak1n Jul 12 '16 at 14:40

2 Answers2

2

Have you tried using simple hard coded rows data? Following code based on your example should work fine. If it works, then there must be problem in populating rows data on the fly, which would need some extra information from you on how your get_rows_data function is working.

def export_csv_from_dict(self, data):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'

    fieldnames = data[0].keys()
    writer = csv.DictWriter(response, fieldnames=fieldnames)

    writer.writeheader()
    writer.writerows(data)
    return response

def accounts_function(self, request):
    rows = [{'first_name': 'Baked', 'last_name': 'Beans'},
            {'first_name': 'Lovely', 'last_name': 'Spam'},
            {'first_name': 'Wonderful', 'last_name': 'Spam'}]
    return self.export_csv_from_dict(rows)
Kevin
  • 901
  • 1
  • 7
  • 15
  • in the chrome debugger it shows the proper content, csv formatted content. But it wont pop up a save to computer action. – rak1n Jul 11 '16 at 20:27
1

There is a sloppy error I have spotted in the base your code:

# rows is a list of dictionary [{'name': 'a'}, {'name': 'b'}]

This seems to be a fatal construction.

  • If you have many dictionaries with the same key, why don't you use a list which will include only the values and iterate through that list for each row?

    rows = ['a', 'b',]

  • If the keys are different:

    keys = data[0].keys()

    The above code will not give you the result you expect. It will only return the key of the first dictionary in the list. You should either iterate through that list and collect the key from each dictionary separately, or construct rows as follows:

    rows = [{'name1': 'a', 'name2': 'b'},]

raratiru
  • 8,748
  • 4
  • 73
  • 113
  • so my data is like this rows = [{'firstname': 'john', 'lastname': 'doe'},{'firstname': 'jane', 'lastname': 'doe'},], also when I was writing to a local csv file, this was working fine. It's just I can't figure out how to download that temporary csv file from the server to my local machine. – rak1n Jul 08 '16 at 22:38
  • You should provide more info about the result that you receive. – raratiru Jul 09 '16 at 10:17