5

I have been wracking my brains in this problem. Is there a way in django to serve multiple files from a single HttpResponse?

I have a scenario where i am looping through a list of json and want to return all those as file form my admin view.

class CompanyAdmin(admin.ModelAdmin):
    form = CompanyAdminForm
    actions = ['export_company_setup']

    def export_company_setup(self, request, queryset):
        update_count = 0
        error_count = 0
        company_json_list = []
        response_file_list = []
        for pb in queryset.all():
            try:
                # get_company_json_data takes id and returns json for the company.
                company_json_list.append(get_company_json_data(pb.pk))
                update_count += 1
            except:
                error_count += 1

        # TODO: Get multiple json files from here.
        for company in company_json_list:
            response = HttpResponse(json.dumps(company), content_type="application/json")
            response['Content-Disposition'] = 'attachment; filename=%s.json' % company['name']
            return response
        #self.message_user(request,("%s company setup extracted and %s company setup extraction failed" % (update_count, error_count)))
        #return response

Now this will only let me return/download one json file as return would break the loop. Is there a simpler way to just append all this in a single response object and return that outside loop and download all json in the list in multiple files?

I looked through a way to wrap all these files into a zip file, but i failed to do so as all the examples that i could find had files with path and name which i don't really have in this case.

UPDATE:

I tried to integrate zartch's solution to get a zip file using following:

    import StringIO, zipfile
    outfile = StringIO.StringIO()
    with zipfile.ZipFile(outfile, 'w') as zf:
        for company in company_json_list:
            zf.writestr("{}.json".format(company['name']), json.dumps(company))
        response = HttpResponse(outfile.getvalue(), content_type="application/octet-stream")
        response['Content-Disposition'] = 'attachment; filename=%s.zip' % 'company_list'
        return response

Since i never had the files to begin with, i thought about just using json dump that i had and adding individual filename. This just creates an empty zipfile. Which i think is expected as i am sure zf.writestr("{}.json".format(company['name']), json.dumps(company)) is not the way to do it. I would appreciate if anyone can help me with this.

Rajat Vij
  • 317
  • 2
  • 6
  • 16
  • you tryed to store in a dictionary and return the dictionary? – Zartch Mar 15 '17 at 15:57
  • Sorry, didn't get you. I already have the list of dictionaries that i want to download as files from my view. I am basically selected a list of objects on an admin view and then calling another method(from actions) to get this list of json extracts which i need to return as files here. – Rajat Vij Mar 15 '17 at 16:14

2 Answers2

6

Maybe if you try to pack all files in one zip you can archive this in Admin

Something like:

    def zipFiles(files):
        outfile = StringIO()  # io.BytesIO() for python 3
        with zipfile.ZipFile(outfile, 'w') as zf:
            for n, f in enumerate(files):
                zf.writestr("{}.csv".format(n), f.getvalue())
        return outfile.getvalue()

    zipped_file = zip_files(myfiles)
    response = HttpResponse(zipped_file, content_type='application/octet-stream')
    response['Content-Disposition'] = 'attachment; filename=my_file.zip'
Edorka
  • 1,781
  • 12
  • 24
Zartch
  • 945
  • 10
  • 25
  • Should the first statement be `response = HttpResponse(json.dumps(company_json_list), content_type="application/json")` as company is just items present in company_json_list. If so, it didnt let me pack it as i got ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION error. – Rajat Vij Mar 15 '17 at 16:48
  • update all the view and the template. I didn't get you. – Zartch Mar 15 '17 at 16:51
  • Sorry, I updated my code. Its in admin actions. I hope this makes it clear and thanks for looking at this. – Rajat Vij Mar 15 '17 at 17:14
  • Yes, i was thinking of doing just that, but i am new to this and not sure how to archive this as we don't really have the files here. Would it be possible to just forward the request or these list of json from here to an export view to get this working? – Rajat Vij Mar 15 '17 at 17:39
  • I updated my answer. Maybe packing the files in a zip works. – Zartch Mar 21 '17 at 13:39
  • Thanks alot! I just went with using individual downloads for now but i definitely need to go and revisit this. I hope this works. I will update my answer once i have a solution to this. :) – Rajat Vij Mar 21 '17 at 17:45
0

I had meet this demand.my solution is using html href and javascript

use server to generate list of download file list

<a href="http://a.json" download='a.json'></a>
<a href="http://b.json" download='b.json'></a>
<a href="http://c.json" download='c.json'></a>
<a href="http://d.json" download='d.json'></a>
<a href="http://e.json" download='e.json'></a>

<script>
    //simulate click to trigger download action
    document.querySelector('a').forEach( aTag => aTag.click());
</script>
nay
  • 1,725
  • 1
  • 11
  • 11