Django view to download a file from server

Viewed 269

I have a views.py that:

  • creates some .xlsx files
  • select the correct .zip and place the file inside

After that, I want this .zip to be automatically downloaded. I did some research and tested some codes but none worked.

I created a "temp" folder in the root of the app where the created files are stored.

simplified view.py

def generate_ws(request,cource,ca_id):
    ca = get_object_or_404(CreditAnalysis,pk=ca_id)
    ca_owners = CAOwner.objects.filter(ca_operation=ca)
    mo_farms = MOFarm.objects.filter(ca_operation=ca)
    misses = []

    generate_owner_mo(ca_owner,misses,city)
    zip_name = 'temp/MOs - ' + str(ca_owner.owner) + '.zip'
    zf = zipfile.ZipFile(zip_name,'w')
    zf.close()

    generate_farm_mo(mo_farm,misses,city)
    generate_production_mo(ca,misses,city,production_city,pks)

    files = glob.glob('temp/*.xlsx')       #SELECT FILES AND PUT IN .ZIP
    for file in files:
        file_key = file.split('.')[0]
        file_key=file_key.split(' - ')
        for ca_owner in ca_owners:
            zip_name = 'temp/MOs - ' + str(ca_owner.owner) + '.zip'
            if str(ca_owner.owner) in file_key:
                zf = zipfile.ZipFile(zip_name,'a')
                new_file_name = file[5:]
                zf.write(file,new_file_name)
                zf.close()                
                break
     files = glob.glob('temp/*.zip')             # GET .ZIP FILES
     for file in files:
         download_mo(request,file)               # CREATE A DOWNLOAD FOR EACH .ZIP FILE

    misses = list(set(misses))

    return render(request,'generate_mo.html',{'misses':misses,})

download_mo

def download_mo(request,file):
    path_to_file = os.path.realpath(file)
    with open(path_to_file,'rb') as fh:
        response = HttpResponse(fh.read())
        file_name = file[5:]                       #WITHDRAW "temp/"
        response['Content-Disposition'] = 'inline; filename=' + file_name
        return response

Everything works correctly except the download which never starts

1 Answers

In order to download a file, you need to return a FileResponse to the user. However, calling an external function that returns a FileResponse won't work because you're not actually returning the FileResponse to the user, in your case the user only receives the render(request, 'generate_mo.html', {'misses':misses,}) so that won't download the files.

You can't download several files one after the others, so I suggest putting them all in a .zip or .tar file so that you can download them as only one file, and only need to return one FileResponse.

As you also need to render your template, what you can do is redirect to your download_mo view on template loading so that your file is downloaded while your template is rendered.

Now, for your download_mo view, just replace your HttpResponse with a FileResponse :

from django.http import FileResponse
def download_mo(request,file):
    path_to_file = os.path.realpath(file)
    response = FileResponse(open(path_to_file, 'rb'))
    file_name = file[5:]
    response['Content-Disposition'] = 'inline; filename=' + file_name
    return response
Related