flask - problem with multiple post request methods - python

I have a page with a search bar that is connected to my database and I am creating a button where the user will be able to update the database by uploading .xlsx file.
I wrote scripts and functions but when I click Submit button I get this error:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. KeyError: 'product'
Everything works ok when I run python function from PyCharm or when I delete search_bar function in main.py and then run the function but it doesn't work if I have search_bar function at all.
Any idea why it isn't working?
main.py
from flask import Flask, render_template, request, redirect, url_for, session, send_file, send_from_directory, flash
from werkzeug.utils import secure_filename
from flask_mysqldb import MySQL
import MySQLdb.cursors
import os
from compare import upload_excel_to_sql
app = Flask(__name__)
#app.route('/content)
def content():
# Check if user is loggedin
if 'loggedin' in session:
# User is loggedin show them the home page
return render_template('content.html', username=session['username'])
# User is not loggedin redirect to login page
return redirect(url_for('login'))
# SEARCH IN DATABASE
#app.route('/content', methods=['GET', 'POST'])
def search_bar():
if 'loggedin' in session:
if request.method == "POST":
cursor = connection.cursor(buffered=True)
product = request.form['product']
# search by project name or title or brand
cursor.execute("USE content_repository")
cursor.execute("""SELECT upload_date,
product_code,
Project_name,
Country,
Brand,
Category,
Title,
Bullet_Points,
Description,
version
FROM product WHERE Project_name LIKE %s OR Title LIKE %s OR Brand LIKE %s""",
(product, product, product))
connection.commit()
data = cursor.fetchall()
# all in the search box will return all the tuples
if len(data) == 0 and product == 'all':
cursor.execute("""SELECT upload_date,
product_code,
Project_name,
Country,
Brand,
Category,
Title,
Bullet_Points,
Description,
version
FROM product""")
connection.commit()
data = cursor.fetchall()
return render_template('content.html', data=data)
return render_template('content.html')
return redirect((url_for('content')))
# UPLOADING AND PROCESSING FILE
UPLOAD_FOLDER = os.path.dirname(os.path.abspath(__file__)) + '/uploads/'
DOWNLOAD_FOLDER = os.path.dirname(os.path.abspath(__file__)) + '/downloads/'
# Allow user to upload only xlsx files'
ALLOWED_EXTENSIONS = {'xlsx'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['DOWNLOAD_FOLDER'] = DOWNLOAD_FOLDER
# Set up the maximum size of the file, in this case it is 10 mb
app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024
# Functions that check if an extension is valid
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/content_repository', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# if user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(UPLOAD_FOLDER, filename))
# we call process_file function and pass the uploaded file path as an argument
filename = upload_excel_to_sql(os.path.join(UPLOAD_FOLDER, filename), UPLOAD_FOLDER)
return redirect(url_for('content', filename=filename))
return render_template('content.html', username=session['username'])
if __name__ == '__main__':
app.run(debug=True)
compare.py
from sqlalchemy import create_engine
import pymysql
import pandas as pd
from aifc import Error
import os
def upload_excel_to_sql(file_path, upload_folder):
"""
Load data from excel to sql database
:param path: path to excel with dataset (str)
:return: True if everything is correct
"""
output_path = os.path.join(upload_folder, file_path)
df_scrapped_data = pd.read_excel(output_path)
for column in df_scrapped_data.columns:
if column.startswith("Unnamed"):
df_scrapped_data.drop([column], inplace=True, axis=1)
engine = create_engine("mysql+pymysql://{user}:{psw}#localhost/{db}".format(user="root", psw="root", db="content"))
df_scrapped_data.to_sql('product', con=engine, if_exists='append', index=False)
return engine
content.html
form element with search bar and with upload and submit elements.
<form method="POST" action="">
<input type="search" placeholder="Search" aria-label="Search" name="product">
<button type="submit">Search</button>
</form>
<form method="POST" action="" enctype="multipart/form-data">
<p><input type="file" name="file"></p>
<p><input type="submit" value="Submit"></p>
</form>

Related

How to prevent uploaded files from having the same name Flask Python

I am trying to build a website in python using flask that takes file uploads and saves them to a folder (called uploads). However, when two files with the same name are uploaded, the first one is overwritten by the last one. How can I prevent this in a way that means that I don't lose any files? Would adding a timestamp to the filename help or would there still be an issue if two files are uploaded at the same time?
Thanks!
Filesystem
FlaskProject:
├───static
├───templates
├───uploads
└───app.py
Html
{%extends "base.html" %}
{%block content%}
<p>
<h2>Upload Below!</h2>
<div></div>
<form action = "http://localhost:5000/upload_complete" method = "POST"
enctype = "multipart/form-data">
<input type = "file" name = "file" />
<input type = "submit"/>
</form>
{% endblock %}
Python
from flask import Flask, redirect, url_for, render_template, request
from werkzeug.utils import secure_filename
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = "D:/Me/FlaskProject/uploads"
#app.route('/upload')
def upload():
return render_template("upload.html", page="Upload Images")
#app.route('/upload_complete', methods = ['GET', 'POST'])
def upload_complete():
if request.method == 'POST':
f = request.files['file']
f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename)))
return redirect(url_for('upload_complete'))
return render_template("upload_complete.html", page="Upload Complete")
if __name__ == '__main__':
app.debug = True
app.run()
app.run(debug = True)
(upload_complete.html is just a thank you screen)
You can generate an uuid and update the filename with it.
You can generate uuid like this,
import uuid
... your code ..
hash_value = uuid.uuid4().hex
f.save(os.path.join(app.config['UPLOAD_FOLDER'], hash_value + secure_filename(f.filename)))

Removed send_file() command from my program but it still sends

I started learning Flask by myself today, and while I was toying around with it I made a small program to download a file, and it worked great.
#app.route('/download')
def download():
path = "Path_to_my_file"
return send_file(path, as_attachment=True)
Now I was changing my program a bit and I removed the 'send_file' function and added some other commands. However, when I tried running the program, the download still happened. I have no idea why though.
My Code:
from flask import *
from flask_sqlalchemy import SQLAlchemy
from werkzeug.utils import secure_filename
import os
usera = ""
UPLOAD_FOLDER = 'I:/Python'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config ['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///downloads.sqlite3'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
user = db.Column(db.String)
download = db.column(db.String)
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/upload', methods=['GET', 'POST'])
def upload_file():
global usera, db
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# if user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
db.session.add(User(user = usera, download = filename))
return render_template('lol.html')
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
'''
#app.route('/login',methods = ['POST', 'GET'])
def login():
global db, user
if request.method == 'POST':
usera = request.form['user']
return render_template('lol.html')
#app.route('/download')
def download():
path = "I:/Python/"
users = User.query.all()
return users
if __name__ == '__main__':
app.run(host='0.0.0.0')
I had faced same issue where flask was returning old files (in your case it is still sending files even if code is changed). This issue is due to the fact that file is cached in browser. Clear the browser cache and your api will start working.

Uploading images to a Flask server using FilePond (React component)

I have a locally hosted Flask server and a small React application. I'm trying to use FilePond as an easy solution for image uploading. FilePond takes care of sending each image to the server.
So the problem I'm obviously having is with the backend code. I've set up my server like this, per Flask's docs
UPLOAD_FOLDER='/images'
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET', 'POST'])
def upload_file():
print(request.files)
if request.method == "POST":
# check if the post request has the file part
if 'file' not in request.files:
print('No file part')
return make_response("No File Part", 400)
file = request.files["file"]
# if user does not select file, browser also submit an empty part
# without filename
if file.filename == '':
print('No selected file')
return make_response("No Selected File", 400)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename) # filenames can be dangerous!
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return make_response("Success", 201)
However, when put a
print(request.files)
statement at the beginning of the upload_file() function, it seems that this is the request the server is receiving:
ImmutableMultiDict([('images', <FileStorage: 'imageName.jpg' ('image/jpeg')>)])
and I have no idea how to deal with that. I don't know if 'images' is where 'file' is supposed to be. I'm just not really sure where to go from here or what to do with the data being received. I don't know what is, I've never seen that <> syntax being used.
Can anyone help?
Here's a pastebin for the whole server-side code
Thank you!
Here's a proof of concept app that lets you upload multiple images using a form:
Note the enctype="multipart/form-data" attribute of the form, without this you cannot upload files.
Also note the multiple attribute of the file input. This allows client to select multiple files. You need to use request.files.getlist() to obtain the list of all uploaded files.
Once you generate the path to save the file, saving a werkzeug.FileStorage object is is just calling its .save(path_to_save) method.
from flask import Flask, request, render_template_string, redirect, abort
from werkzeug import secure_filename
from pathlib import Path
UPLOAD_DIR: Path = Path(__file__).parent / 'uploads'
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
app = Flask(__name__)
def is_valid_upload(upload) -> bool:
# some validation logic
return Path(upload.filename).suffix.lower() in ['.jpg', '.jpeg']
#app.route('/', methods=['GET', 'POST'])
def upload():
html = '''
<form action='/' method='POST' enctype="multipart/form-data">
<input type="file" name='images' multiple>
<button>Upload</button>
</form>
'''
if request.method == 'GET':
return html
uploaded_files = request.files.getlist('images')
if not uploaded_files or not uploaded_files[0].filename:
return redirect('/')
valid_uploads = list(filter(is_valid_upload, uploaded_files))
if not valid_uploads:
return 'invalid image(s)', 400
for upload in valid_uploads:
filename = secure_filename(upload.filename)
save_path = str(UPLOAD_DIR / filename)
upload.save(save_path)
return 'uploaded'
if __name__ == "__main__":
app.run()

Getting a requested URL not found error when running flask code

Created a web app and have managed to build a function to clean up csv files from Google my Business exports. However when I run the function with the code I have written I get the following error message:
Not Found
The requested URL was not found on the server. If you entered the URL
manually please check your spelling and try again.
Not sure where I am going wrong
mport os
import pandas as pd
from flask import Flask, request, redirect, url_for
from flask import Flask, make_response
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = './Downloads/gmbreports'
if not os.path.exists(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
ALLOWED_EXTENSIONS = 'csv'
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transform(text_file_contents):
disc = open('clean.csv')
disc2 = open('clean_two.csv','w')
#cleaning up csv
for row in disc:
row = row.strip()
row = row[1:-1]
row = row.replace('""','"')
disc2.write(row+'\n')
disc2.close()
disc.close()
discovery = pd.read_csv('clean_two.csv')
discovery_clean = discovery.iloc[1:]
cols = list(discovery_clean.columns[4:])
discovery_clean[cols] = discovery_clean[cols].apply(pd.to_numeric,errors='coerce')
return discovery_clean
#app.route('/', methods=['GET', 'POST'])
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']
if file.filename == '':
flash('You need to upload a csv file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('uploaded_file',
filename=filename))
return '''
<!doctype html>
<title>Google My Business Discovery Report Builder</title>
<h1>Upload GMB Discovery csv</h1>
<form action="\transform" method="post" enctype="multipart/form-data">
<p><input type="file" name="file">
<input type="submit" value=Upload>
</form>
'''
#app.route('/transform',methods=["POST"])
def transform_view():
request_file=request.files['file']
request_file.save('clean.csv')
if not request_file:
return "No file"
result = transform()
print(result)
response = make_response(result)
response.headers["Content-Disposition"] ="attachment; filename=result.csv"
return response
if __name__=='__main__':
app.run()
Note: I get this error message after running the script and uploading a csv. The desired outcome is uploading a csv, and showing it on my screen as a cleaned up data table
There are multiple problems here. First, Wondercricket is correct about the form action. It needs to be changed to "/transform".
Once that's done, you're still getting an Internal Server Error. In this case, your transform function is defined as taking a single parameter, but it's not being called with one. Simply change
def transform(text_file_contents):
to
def transform():
That should allow the upload to happen, and the transform will now run. However, there's still one last problem. transform returns a pandas DataFrame, which Flask can't use as a response. Change
response = make_response(result)
to
response = make_response(result.to_csv())
and you should be good to go.

How to download a csv file from mysql table after clicked the file name

everyone I need your help to fix my code. I would like to download a csv file form mysql db table. I have import the file name to the table. but when I click the file name I got this http://192.168.1.6/phpmyadmin/2017-08-09065534.csv (The requested URL /phpmyadmin/2017-08-09065534.csv was not found on this server.) But when I delete the /phpmyadmin/ in the browser, like this 192.168.1.6/2017-08-09065534.csv , the file will automatically downloaded. So How do I delete the phpmyadmin ?? Or any idea?
this is my code.
enter code here
import os
from flask import Flask, request, redirect, url_for, send_from_directory
from werkzeug import secure_filename
import MySQLdb
import glob
UPLOAD_FOLDER ="/var/www/html"
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'csv'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
# this has changed from the original example because the original did not work for me
return filename[-3:].lower() in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['file']
if file and allowed_file(file.filename):
print '**found file', file.filename
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
conn = MySQLdb.connect (host="192.168.1.6", port=3306, user="root",passwd="12345fitri",db="myDb")
x = conn.cursor()
#print 'filename'
#sql = "INSERT INTO mine (what) values (%s)", (filename,)
os.chdir(UPLOAD_FOLDER)
dirfiles=glob.glob("*.csv")
for file_name in dirfiles:
#print file_name
if file_name==filename:
try:
cursor = conn.cursor()
file_path= os.path.join(app.config['UPLOAD_FOLDER'], filename)
#print sql.format (file_path)
cursor.execute("INSERT INTO mine (what) VALUES (%s)", (filename,))
conn.commit()
print "hello"
except Exception:
# Rollback in case there is any error
conn.rollback()
# for browser, add 'redirect' function on top of 'url_for'
return url_for('uploaded_file',
filename=filename)
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
'''
#app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, threaded=True,debug=True)

Categories