Home > Enterprise >  Uploading file in Flask with only .csv allowed extension
Uploading file in Flask with only .csv allowed extension

Time:02-05

I'm creating a form that allows you to upload a .csv file and then on submit, posts the values inside the csv file to the database.

My problem is that I want to be able to use request.files[] to implement a logic check that only accepts .csv extension files for upload, however, I am not able to use request.files[] when trying to open my csv file with with open(f, 'r') below.

I get this error: "Unexpected type(s): (FileStorage, str) Possible type(s): (Union[str, bytes, PathLike[str], PathLike[bytes], int], str)..."

If I used request.form[], I don't have the error with opening the file, however, then I can't use the "filename" attribute for the logic check as that requires request.files[].

Here is my routes file:

allowed_extensions = ['csv']

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

@main.route("/reading_csv", methods=['POST'])
def reading_csv():
    if request.method == 'POST':
        f = request.files['csvfile']
        # logic check
        if not allowed_file(f.filename):
            flash("Only CSV Files Allowed", 'danger')
            return redirect(url_for('main.alloc_summ'))
        # opening file, reading it in, and inserting values to database
        with open(f, 'r') as csv_file:
            csv_reader = csv.DictReader(csv_file, delimiter=',')
            all_values = [tuple(line.values()) for line in csv_reader]

        con = sql.connect('<hidden path url>')
        cur = con.cursor()

        cur.executemany('INSERT INTO allocation_summary \
                        (state, eligible_applicant, recipient, amount, funding_source_id) \
                            VALUES (?,?,?,?,?)', all_values)
        con.commit()

        cur.close()
        con.close()

        flash("Allocations Added Successfully")
        return redirect(url_for('main.alloc_summ'))

Here is the HTML:

                    <td>
                        <form  action="{{url_for('main.reading_csv')}}" method="post" enctype="multipart/form-data">
                            <input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" value =""> <br>
                            <input style="margin-bottom: 10px;" type="submit" name="" value="Submit">
                        </form>
                    <br>
                    </td>

I can't open my file using the "f" variable that holds the requested file.

Is there any work around to this? TIA!!

CodePudding user response:

Use .save() method to save your file, don't try to open it

f.save(path: str, filename: str)

Upd:

Read Flask: How to upload file to understand the basic of multipart handling in Flask

CodePudding user response:

FileStorage is a file-like object that understands standard reading functions. It corresponds to a temporary file opened in binary mode. So you don't have to open this file again.
In order to be able to read a CSV file, it should be opened in text mode. This results in a contradiction.
The following example should show you one way to meet your requirements.

import csv, io

allowed_extensions = ['csv']

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

@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST' and 'csvfile' in request.files:
        f = request.files['csvfile']
        if f.filename != '' and allowed_file(f.filename):
            with io.TextIOWrapper(f) as fp:
                reader = csv.DictReader(fp, delimiter=',')
                values = [tuple(line.values()) for line in reader]
                print(values)
                # ...
    return render_template('upload.html')
<form  action="{{url_for('upload')}}" method="post" enctype="multipart/form-data">
    <input type="file" accept="text/csv" name="csvfile" />
    <input type="submit" />
</form>

Please keep in mind that a file can become very large and contains data that should be validated before it is included in your database. Perhaps saving the file as @sudden_appearance describes is a more appropriate solution.

  •  Tags:  
  • Related