I've checked on stackoverflow and other places and everywhere they use files.filename to check if a file is available or not. If I do this I get the message
AttributeError: 'list' object has no attribute 'filename'
Do I miss something? Or is there another way to check if the user has selected a file to upload?
my HTML:
<form method="POST" enctype="multipart/form-data" action="/upload">
<label>Choose a problem report file (*.zip).
<input type="file" name="file[]" multiple="" accept=".zip">
<input type="submit" value="Upload problem report(s)">
</label>
</form>
my python
import flask
from werkzeug.wrappers import request
import os
app = flask.Flask("upload")
UPLOAD_FOLDER = './upload'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def get_html(page_name):
html_file = open(page_name + ".html")
content = html_file.read()
html_file.close()
return content
#app.route("/upload", methods=["POST"])
def upload():
files = flask.request.files.getlist("file[]")
if files.filename !='':
for file in files:
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
return get_html("index")
It's not the best code I know, but if I leave out the check for the filename the upload works.
It should be something like this:
files = flask.request.files.getlist("file[]")
for file in files:
if file.filename !='':
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
As the error message suggested, your get a list, and a list has not filename attribute, so you need to check the items in the list.
Related
Working with flask backend, a csv file is being uploaded to the server with the following html.
<form method="POST" enctype="multipart/form-data" action="/csvUpload">
<input type="file" id="myFile" name="filename" accept=".csv">
<input type="submit">
</form>
On the routes.html in flask, we have the following function,
#app.route('/csvUpload', methods=['POST'])
def csvUpload():
try:
if request.method == 'POST':
if request.files:
uploaded_file = request.files['filename']
data = uploaded_file.stream.read() # This line uses the same variable and worked fine
#Convert the FileStorage to list of lists here.
return data
except Exception as e:
traceback.print_exc()
return "Alas! The code didnt work."
The required output is like the output of a csv.reader(file, 'r'), when reading files from the local system with a static path. The reason for that is that I want to use this csv to update tables in a database attached with the backend.
Try the following method which uses the io.StringIO module:
#app.route('/csvUpload', methods=['POST'])
def csvUpload():
if request.method == 'POST':
if request.files:
uploaded_file = request.files['filename']
data = uploaded_file.stream.read() # This line uses the same variable and worked fine
#Convert the FileStorage to list of lists here.
stream = io.StringIO(data.decode("UTF8"), newline=None)
reader = csv.reader(stream)
for row in reader:
print(', '.join(row))
return data
Some test data returns the following to the terminal on upload:
Name, Age
Kevin, 15
Perry, 14
Paul, 30
This code should allow you achieve what you want.
I'm trying to work file upload example in this website https://www.tutorialspoint.com/python/python_cgi_programming.htm
I have written a .py file. When i run this code, following error is occurs;
Traceback (most recent call last):
File "C:/xampp/cgi-bin/file_upload.py", line 9, in <module>
fileitem = form['filename']
File "C:\Python3\lib\cgi.py", line 604, in __getitem__
raise KeyError(key)
KeyError: 'filename'
And my .py file is below:
#!C:/Python3/python.exe
import cgi, os
import cgitb; cgitb.enable()
form = cgi.FieldStorage()
# Get filename here.
fileitem = form['filename']
# Test if the file was uploaded
if fileitem.filename:
# strip leading path from file name to avoid
# directory traversal attacks
fn = os.path.basename(fileitem.filename)
open('F:/gelen/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
print ("""\
Content-Type: text/html\n
<html>
<body>
<form enctype="multipart/form-data"
action="/cgi-bin/file_upload.py" method="post">
<p>File: <input type="file" name="filename" /></p>
<p><input type="submit" value="Upload" /></p>
</form>
<p>%s</p>
</body>
</html>
""" % (message,))
How Can i solve this problem and why program doesn't see filename i don't understand
If the directory where the script is running is /path/to/dir then the /path/to/dir/files directory must exist. If it does not it will fail.
and also to upload a file the HTML form must have the enctype attribute set to multipart/form-data.
Perhaps it is late for the person who asked, but I came across a similar problem. The following is what worked for me. As your error message shows the problem is coming from the line. fileitem = form['filename'] We can run the file in the browser as http://localhost:xxxx/file_upload.py What you'll see is the 'browse' button and the 'upload' button. Unless you browse and load some file the 'form' object won't be populated. It wouldn't contain the key 'filename', yet. We get the keyerror. So we need to put it inside an if statement. I also found some formatting error with the html part of the code. I slightly edited the code which is pasted below, runs well on Linux.
#!/usr/bin/python3
import cgi, sys, os
import cgitb; cgitb.enable()
form = cgi.FieldStorage()
print('Content-type: text/html')
sys.path.insert(0, os.getcwd())
message = None
# Test if the file is loaded for the upload
if 'filename' in form:
fileitem = form['filename']
fn = os.path.basename(fileitem.filename)
open('/home/jk/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
replyhtml = """
<html>
<body>
<form enctype="multipart/form-data" action="/cgi-bin/file_upload.py" method="post">
<p>File: <input type="file" name="filename" /></p>
<p><input type="submit" value="Upload" name=action/></p>
</form>
<p>%s</p>
</body>
</html>
"""
print(replyhtml % message)
I believe you have your server running in the current working directory. And the .py file need to be in the cgi-bin folder. A simple http server script:
import os
from http.server import HTTPServer, CGIHTTPRequestHandler
servaddr = ("localhost", 8888)
#http.server.SimpleHTTPRequestHandler(request, client_address, server)
server = HTTPServer(servaddr, CGIHTTPRequestHandler)
server.serve_forever()
References:
Programming Python, Mark Lutz, 4th edition, Chapter1
https://www.youtube.com/watch?v=oQ9FwkhUN1s
http://cgi.tutorial.codepoint.net/file-upload
Also if you are uploading images to an ec2 linux server then the folder you want to upload your files into must have the permissions drwxrwxrwt.
chmod 777 -R myfolder
chmod o+t -R myfolder
this worked for me
Referred from here
I'm trying to write a simple flask program that will create a web page in which it receives a file (by uploading it), and then using that file's data and displaying a filtered part of it in my web page, I just cant seem to understand how to do that.
This is the code I used to upload the file, which worked fine.
import os
from flask import Flask, request, redirect, url_for
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = 'C:/Users/ohadt/PycharmProjects/logFiles'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'log'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
#app.route('/', 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 a 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))
return redirect(url_for('read_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>
'''
Then I tried writing the method for opening the file and reading the data from it, but I couldn't figure how to do that, could you please help me understand how to read the file content and presenting a filtered version of it on my site?
Thanks!
You already saved it here
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
just open it up and read as you work with any other files, example:
#app.route('/read_file', methods=['GET'])
def read_uploaded_file():
filename = secure_filename(request.args.get('filename'))
try:
if filename and allowed_filename(filename):
with open(os.path.join(app.config['UPLOAD_FOLDER'], filename)) as f:
return f.read()
except IOError:
pass
return "Unable to read file"
You need to carefully sanitize user input here, otherwise method could be used to read something unintended (like app source code for example). Best is just not grant user ability to read arbitrary files - for example when you save a file, store it's path in database with some token and give user just this token:
filename = secure_filename(file.filename)
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
token = store_in_db(filepath)
return redirect(url_for('read_uploaded_file',
token=token))
Then accept a token, not a filename when you read a file:
#app.route('/read_file', methods=['GET'])
def read_uploaded_file():
filepath = get_filepath(request.args.get('token'))
try:
if filepath and allowed_filepath(filepath):
with open(filepath) as f:
return f.read()
except IOError:
pass
return "Unable to read file"
Tokens need to be random, long, not guessable (uuid4 for example) - otherwise there will be a possibility to easily read other users files. Or you need to store relation between file and user in database and check it too. Finally, you need to control size of file uploads to prevent user from uploading huge files (app.config['MAX_CONTENT_LENGTH']) and control amount of info you read in memory when you display "filtered" file content (f.read(max_allowed_size)).
I'm trying to set up a file upload web form that is processed by a python script. When I select a file and click upload, it says that no file was uploaded. The file field of the fileitem object is None. This script is running on a lighthttpd server.
The code for the script is here:
#!/usr/bin/env python
import cgi, os
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
# A nested FieldStorage instance holds the file
fileitem = form['filename']
print "----"
print "filename", fileitem.filename
print "file", fileitem.file
print "----"
message = ''
if fileitem.file:
# It's an uploaded file; count lines
linecount = 0
while 1:
line = fileitem.file.readline()
if not line: break
linecount = linecount + 1
message = linecount
# Test if the file was uploaded
if fileitem.filename:
# strip leading path from file name to avoid directory traversal attacks
fn = os.path.basename(fileitem.filename)
open('/var/cache/lighttpd/uploads/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message += 'No file was uploaded'
print """\
Content-Type: text/html\n
<html><body>
<p>%s</p>
</body></html>
""" % (message,)
The html file is here:
<html>
<head>
<title>RepRap Pinter</title>
</head>
<body>
<H1>RepRap Printer</H1>
<form action="cgi-bin/start_print.py" method="post" encrypt="multipart/form-data">
<p><input type="file" name="filename" id="file"></p>
<p><input type="submit" value="Upload"></p>
</form>
</body>
</html>
And the output is:
----
filename None
file None
----
Content-Type: text/html
<html><body>
<p>No file was uploaded</p>
</body></html>
Any ideas as to why the file isn't being uploaded?
Your problem seems to be here:
<form ... encrypt="multipart/form-data">
The attribute you are looking for isn't encrypt, it's enctype. Since you are missing the correct parameter your encoding isn't multipart-formdata so file uploads are ignored.
You are using the wrong attribute name:
<form action="cgi-bin/start_print.py" method="post" encrypt="multipart/form-data">
The correct attribute is enctype, not encrypt:
<form action="cgi-bin/start_print.py" method="post" enctype="multipart/form-data">
I'm trying to create a PDF with checkboxes that can be checked (using python). I've been trying to use pisa to generate the pdf and have looked around the internet and tried different examples but I cannot find out how to make an editable PDF.
This is my most recent attempt:
import cStringIO
import ho.pisa as pisa
import os
# shortcut for dumping all logs on screen
pisa.showLogging()
def HTML2PDF(data, filename, open=False):
"""
Simple test showing how to create a PDF file from
PML Source String. Also shows errors and tries to start
the resulting PDF
"""
pdf = pisa.CreatePDF(cStringIO.StringIO(data), file(filename, "wb"))
if open and not(pdf.err):
os.startfile(str(filename))
return not pdf.err
if __name__=="__main__":
HTMLTEST = """
<html>
<body>
<form name="deleteForm" method="get" action="">
User 1 <input type="checkbox" name="user" value="delete" />
</form>
</body>
</html>
"""
HTML2PDF(HTMLTEST, "test.pdf", open=True)
The form gives me an error:
Traceback (most recent call last):
File "C:/Users/horeth/PycharmProjects/Reportlab/HTMLtoPF/Main.py", line 32, in
HTML2PDF(HTMLTEST, "test.pdf", open=True)
File "C:/Users/horeth/PycharmProjects/Reportlab/HTMLtoPF/Main.py", line 14, in HTML2PDF
pdf = pisa.CreatePDF(cStringIO.StringIO(data), file(filename, "wb"))
IOError: [Errno 13] Permission denied: 'test.pdf'
The check boxes are for readers to decide if a user needs to be deleted or not.
I'm wondering if there is a way to create an editable PDF document with Python. This is just one of the attempts I've made so far, as an example.
Possible reasons. You don't have write permission to the directory. The file already exists but you do not have write access to it.
import cStringIO as StringIO
from xhtml2pdf import pisa
from django.template.loader import get_template
from django.template import Context
from cgi import escape
def render_to_pdf(template_path, context_dict):
template = get_template(template_path)
html = template.render(context_dict)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-
1")), dest=result)
if not pdf.err:
return HttpResponse(result.getvalue(),
content_type='application/pdf')
return HttpResponse('We had some errors<pre>%s</pre>' %
escape(html))
Call this function
def myview(request):
return render_to_pdf('HTMLTEST.html', { 'pagesize':'A4',})
create a seperate html file
HTMLTEST.html
<html>
<body>
<form name="deleteForm" method="get" action="">
User 1 <input type="checkbox" name="user" value="delete" />
</form>
</body>
</html>