DEV Community

Suttipong Kullawattana
Suttipong Kullawattana

Posted on

How to upload files with Flask API

In this article, I will present code with python about how to upload files with flask API. Before you will start development, I want to you checkup and install the python library , Preparing to set up a virtual environment (env) for development with $ python3 -m venv venv and the active environment with $ source venv/bin/activate

Next step, We will install flask with $ pip install flask and create a folder in the project.

app.py
/ static
  => css
     / style.css
  => img
     / upload_icon.png
     / success_icon.png
/ templates
  => index.html
  => download.html
Enter fullscreen mode Exit fullscreen mode

For the last one, I will install $ pip3 install -r requirements.txt and freeze the library with $ pip freeze > requirements.txt to finish the setup.

After finishing setting up, I will be imported JSON, flask template, and utils of the secure file name. You can follow up on the code below.

import os
import json
from flask import Flask, request, render_template, flash, redirect, url_for, send_from_directory
from werkzeug.utils import secure_filename
Enter fullscreen mode Exit fullscreen mode

In the second step, I have to provide constants that allow checking file format extensions (example: for checking ".txt" file)

ALLOWED_EXTENSIONS = {'txt'}
Enter fullscreen mode Exit fullscreen mode

In the third step, I have to create a new instance for the configuration file format on the code below.

application = Flask(__name__)
application.secret_key = os.urandom(24)
application.config['UPLOAD_FOLDER'] = 'data'
application.config['MAX_CONTENT_LENGTH'] = 4 * 1024 * 1024  # 4MB max-limit.
Enter fullscreen mode Exit fullscreen mode

And I have to create an extension for checking allowed files with ALLOWED_EXTENSIONS

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.',1)[1].lower() in ALLOWED_EXTENSIONS  
Enter fullscreen mode Exit fullscreen mode

The fourth step, I have to create API for uploading files with the browser. If It has a user request to upload the file with localhost IP http://127.0.0.1:5000/, the system will be checking the file part and read the text in document.

# home page
@application.route('/', methods=['POST', 'GET'])
def upload_file():
    if request.method == 'POST':
       if 'file' not in request.files:
          flash('No file part')
          return redirect(request.url)

       file = request.files['file']

       read_text = []
       for text in request.files.get('file'):
          read_text.append(str(text).replace("b'",""))
       print(read_text[0])

       # if the user does not select a file, the browser submits an empty file without a filename.
       if file.filename == '':
         flash('No selected file')
         return redirect(request.url)

       # if the user submits a file with the correct format
       if file and allowed_file(file.filename):
         filename = secure_filename(file.filename)
         file.save(os.path.join(application.config['UPLOAD_FOLDER'], filename))
         os.remove(os.path.join(application.config['UPLOAD_FOLDER'], filename))
         return redirect(url_for('download_file'))

    return render_template('index.html')
Enter fullscreen mode Exit fullscreen mode

After creating the upload file API already. So, I will create a download file API.

# download page
@application.route('/download', methods=['POST', 'GET'])
def download_file():
    if request.method == 'POST':
        if request.form['Download Result File'] == 'Download File':
            return send_from_directory(application.config['UPLOAD_FOLDER'], 'result_file.txt')
Enter fullscreen mode Exit fullscreen mode

For the HTML side, I have to create index.html and download.html on templates folder.

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
    <title>Download File</title>
</head>

<body>
    <div class="container">
        <section class="vh-100 gradient-custom">
            <div class="text-center justify-content-between py-4 px-4 px-xl-5 bg-dark">
                <div class="text-white mb-2 mb-md-0">
                    <p>Download File</p>
                </div>
            </div>
            <div class="container-fluid h-custom py-4">
                <div class="h-100">
                    <div class="row d-flex justify-content-center align-items-center h-100">
                        <div class="col-12 col-md-9 col-lg-7 col-xl-6">
                            <div class="card" style="border-radius: 15px;">
                                <div class="card-body p-5">
                                    <form method=post enctype=multipart/form-data>
                                        <div style="text-align:center;">
                                            <div class="form-outline mb-4">
                                                <input type=file name=file>
                                            </div>
                                            <div class="form-outline mb-4">
                                                <button type=submit class="btn btn-primary">Upload</button>
                                            </div>
                                        </div>
                                    </form>

                                    {% with messages = get_flashed_messages() %} {% if messages %}
                                    <ul class=flashes>
                                        {% for message in messages %}
                                        <li>{{ message }}</li>
                                        {% endfor %}
                                    </ul>
                                    {% endif %} {% endwith %}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

download.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
    <title>Download File Success</title>
</head>

<body>
    <div class="container">
        <section class="vh-100 gradient-custom">
            <div class="container-fluid h-custom py-4">
                <div class="h-100">
                    <div class="row d-flex justify-content-center align-items-center h-100">
                        <div class="col-12 col-md-9 col-lg-7 col-xl-6">
                            <div class="card" style="border-radius: 15px;">
                                <div class="card-body p-5">
                                    <h2 class="text-uppercase text-center mb-5">Download result file</h2>
                                    <form method=post>
                                        <div style="text-align:center;">
                                            <div class="form-outline mb-4">
                                                <input type="submit" name="Download Result File" value="Download BPMN File">
                                            </div>
                                        </div>
                                    </form>
                                    <div style="text-align:center;">
                                        <a href="{{url_for('upload_file')}}">Back to Upload File</a>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

Result app.py

import os
import json
from flask import Flask, request, render_template, flash, redirect, url_for, send_from_directory
from werkzeug.utils import secure_filename

ALLOWED_EXTENSIONS = {'txt'}

application = Flask(__name__)
application.secret_key = os.urandom(24)
application.config['UPLOAD_FOLDER'] = 'data'
application.config['MAX_CONTENT_LENGTH'] = 4 * 1024 * 1024  # 4MB max-limit.

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.',1)[1].lower() in ALLOWED_EXTENSIONS

# home page
@application.route('/', methods=['POST', 'GET'])
def upload_file():
    if request.method == 'POST':
       if 'file' not in request.files:
          flash('No file part')
          return redirect(request.url)

       file = request.files['file']

       read_text = []
       for text in request.files.get('file'):
          read_text.append(str(text).replace("b'",""))
       print(read_text[0])

       # if the user does not select a file, the browser submits an empty file without a filename.
       if file.filename == '':
         flash('No selected file')
         return redirect(request.url)

       # if the user submits a file with the correct format
       if file and allowed_file(file.filename):
         filename = secure_filename(file.filename)
         file.save(os.path.join(application.config['UPLOAD_FOLDER'], filename))
         os.remove(os.path.join(application.config['UPLOAD_FOLDER'], filename))
         return redirect(url_for('download_file'))

    return render_template('index.html')

# download page
@application.route('/download', methods=['POST', 'GET'])
def download_file():
    if request.method == 'POST':
        if request.form['Download Result File'] == 'Download File':
            return send_from_directory(application.config['UPLOAD_FOLDER'], 'result_file.txt')
Enter fullscreen mode Exit fullscreen mode

Top comments (0)