Luiz Henrique Rochelle
Luiz Henrique Rochelle

Reputation: 100

Django view to download a file from server

I have a views.py that:

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

Upvotes: 2

Views: 5543

Answers (1)

Balizok
Balizok

Reputation: 1038

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 other, 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, you can 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, 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

Upvotes: 4

Related Questions