Home > OS >  Django Gunicorn Nginx Python -> Link to download file from webserver
Django Gunicorn Nginx Python -> Link to download file from webserver

Time:05-27

On my webpage served by a Debian web server hosted by amazon-lightsail behind nginx and gunicorn, a user can send a request to start a Django view function. This function add some work to a background process and check every 5s if the background process created a file. If the file exists, the view sends a response and the user can download the file. Sometimes this process can take a long time and the user get a 502 bad gateway message. If the process takes too long, I like to send the user an email with a link where he can download the file from the web server. I know how to send the email after the process is finished, but I don't know how to serve the file to the user by a download link.

This is the end of my view function:

    print('######### Serve Downloadable File #########')
    while not os.path.exists(f'/srv/data/ship_notice/{user_token}'):
        print('wait on file is servable')
        time.sleep(5)
    
    # Open the file for reading content
    path = open(filepath, 'r')
    # Set the mime type
    mime_type, _ = mimetypes.guess_type(filepath)
    # Set the return value of the HttpResponse
    response = HttpResponse(path, content_type=mime_type)
    # Set the HTTP header for sending to browser
    response['Content-Disposition'] = f"attachment; filename={filename}" 
    # Return the response value
    return response

Another model function which sends the mail to the user after process is finished:

def send_mail_precipitation(filepath, user_token, email):
    from django.core.mail import EmailMessage
    import time
    import os
    
    while not os.path.exists(f'/srv/data/ship_notice/{user_token}'):
        print('wait 30secs')
        time.sleep(30)
            
    msg = EmailMessage(
        subject = 'EnviAi data',
        body = 'The process is finished, you can download the file here.... ',
        to = [email]
    )
    msg.send()

The file is too big to send it with msg.attach_file(filepath)

What options do I have to send the user a link to download these files. Do I need to set up a ftp server/folder, or what kind of options do I have? And what kind of work do I have to do when I want that the link is only 72h valid? Thanks a lot!

Update
One way would be to copy the file to the static folder, which is available to the public. Should I avoid this approach for any reason?

CodePudding user response:

Not a straight answer but a possible way to go.

Such a long-running tasks are usually implemented with additional tool like Celery. It is a bad practice to let view/api endpoint run as long as it takes and keep requesting process waiting until completed. Good practice is to give response as fast as you can.

In your case it would be:

  • create a celery task to build your file (creating a task is fast)
  • return task id in response
  • request task status from frontend with given task id
  • when task is done file URL should be returned

It is also possible to add on_success code which will be executed (started by Celery automatically) when task is done. You can call your email_user_when_file_is_ready function in reaction on this event.

To make files downloadable you can add a location to the nginx config same as you did for static and media folders. Put your files to the location mapped folder and that's it. Give the user URL to your file.

  • Related