I'm trying to implement a system of uploading a file (image) to the server running pyramid. Right now, this code gives me an AttributeError: 'unicode' object has no attribute 'file' exception:
Server-side:
session = Session()
username = authenticated_userid(request)
if username == None:
return HTTPNotFound()
else:
user = session.query(User).filter(User.username == username).first()
if 'photo.submitted' in request.params:
input_file = request.POST['file_input'].file
tmp = '../static/images/%s' % (session.query(ProfilePic).order_by(-ProfilePic.photo_id).first().photo_id + 1)
open(tmp, 'w').write(input_file.read())
tmp.close()
return Response('OK')
return {}
HTML:
<html>
<body>
<form action="/settings" method="post">
<input type="file" name="file_input" value="Choose image" />
<p><input type="submit" name="photo.submitted" value="Save" /></p>
</form>
</body>
</html>
Something that seems simple, but won't work. I was trying to follow this tutorial, but it seems it only works with video/audio files. How could I make this work?
For file uploads, you need to alter the form enctype to use multipart/form-data:
<html>
<body>
<form action="/settings" method="post" enctype="multipart/form-data">
<input type="file" name="file_input" value="Choose image" />
<p><input type="submit" name="photo.submitted" value="Save" /></p>
</form>
</body>
</html>
Related
I have two input buttons. One is for uploading a file, and the other one is a submit button that adds the uploaded file to the database.
My problem is, after I submit the file, the first button that's used for uploading goes back to "No file chosen" next to the button. However, I want the uploaded file name to "stick" to the UI/html page as the file chosen.
Here is my File class:
class Files(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, unique=True, nullable=False)
data = db.Column(db.LargeBinary)
Here is my HTML code:
<td>
<form class="" action="{{url_for('main.upload_file')}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{row.id}}">
<input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" id="upload" value ="{{row.name}}"> <br>
<input style="margin-bottom: 10px;" type="submit" name="" value="Submit"> <br>
</form>
<a href={{ url_for('main.files') }}>Go to Downloads Page</a>
<br>
</td>
I've tried making the value attribute equal to the file name getting passed in ex. value ="{{row.name}}" for the file type <input> above, but that doesn't keep the file chosen name on the page after submission either. I can't find any videos or posts that deal with this problem, so I would really appreciate any guidance. TIA!
I think setting a default value for an input field of type file is forbidden for security reasons.
However, if you want to keep the name of the selected file, you can aim for a transfer with AJAX. Here you can suppress the standard behavior of the form. The page is not reloaded and the form is not reset.
The example below shows you how it works.
Flask (app.py)
from flask import Flask
from flask import (
render_template,
request,
)
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload-file', methods=['POST'])
def upload_file():
if 'csvfile' in request.files:
file = request.files['csvfile']
if file.filename != '':
# handle file here!
return '', 200
return '', 400
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form name="my-form" method="post">
<input type="file" name="csvfile" />
<input type="submit" />
</form>
<script type="text/javascript">
((uri) => {
const elem = document.querySelector('form[name="my-form"]');
elem.addEventListener('submit', evt => {
evt.preventDefault();
const formData = new FormData(evt.target);
fetch(uri, {
method: 'post',
body: formData
}).then(resp => {
if (resp.status === 200) {
console.log('Submit successful.');
}
});
})
})({{ url_for('.upload_file') | tojson }});
</script>
</body>
</html>
I don't know if it is possible to default the value the file-input field shows but what you could do is just have a row above the input field showing the currently uploaded/chosen file (if there is any). So something like this:
<td>
<form class="" action="{{url_for('main.upload_file')}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{row.id}}">
{% if row.name %}
<p>Currently chosen file: {{row.name}}</p>
<p>You can select a new file below</p>
{% endif %}
<input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" id="upload"> <br>
<input style="margin-bottom: 10px;" type="submit" name="" value="Submit"> <br>
</form>
<a href={{ url_for('main.files') }}>Go to Downloads Page</a>
<br>
</td>
I'm new to Python and trying to develop simple web application.
In the code below I am trying to retrieve values from DB and rending on HTML page
I'm able to see the HTML page but not values passed. Please help me here.
Python code
#app.route('/userDetails', methods=['POST', 'GET'])
def userDetails():
if request.method == 'POST':
print('in get method')
userid = request.form['userId']
print('user id ', userid)
conn = mysql.connect()
cursor = conn.cursor()
# Get User Details
print('execut sql')
result = cursor.execute("SELECT * FROM tbl_user WHERE user_id= %s", [userid])
if result > 0:
data = cursor.fetchall()
for row in data:
userId = row[0]
name = row[1]
userName = row[2]
password = row[3]
return render_template("userDetails.html", userId=userId, name=name, userName=userName, password=password)
else:
return render_template('index.html')
cursor.close()
HTML code below.
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<title>Python Flask Bucket List App</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h3 class="text-muted">Python Flask App </h3>
</div>
<div class="jumbotron">
<h1>Display User Details</h1>
<div class="jumbotron">
<form class=class="form-userDetails, action="/userDetails", method="POST">
User ID:<input type="text" name="userId" class="form-control">
Name <output name="name" id="name" for="userId" class="form-control"></output>
User Name <output name="userName" id="userName" for="userId" class="form-control"></output>
Password <output name="password" id="password" for="userId" class="form-control"></output>
</br>
<button id="btnretive" class="btn btn-lg btn-primary btn-block" type="submit">Retrive</button>
</form>
</div>
<div class="Footer">
<footer class="footer">
<p>© Company 2015</p>
</footer>
</div>
</div>
</body>
</html>
#DRaj, you are using <output> tag in incorrect way. From the specification,
The HTML Output element () is a container element into which a site or app can inject the results of a calculation or the outcome of a user action.
For more info and example refer to this Mozilla page.
Now,
Flask uses Jinja2 template engine for its HTML rendering. So, the correct way to output values would be to enter a python variable inside Expression delimiters {{ ... }} in the HTML and pass the variables to render_template method.
i.e.
<form class=class="form-userDetails, action="/userDetails", method="POST">
User ID:<input type="text" name="userId" class="form-control">
Name: {{ name }}
User Name: {{ userName }}
Password: {{ password }}
</br>
<button id="btnretive" class="btn btn-lg btn-primary btn-block" type="submit">Retrive</button>
</form>
and the python code should be:-
return render_template("userDetails.html", name=name, userName=userName, password=password)
Refer to this Jinja template designer documentation for more information.
I already saw similar questions here describing same problem, peoples gives there answers and someones even respond it helped, but nothing from it totally works for me.
This is my code:
<html>
<body>
<form action = "/anomalydetector" enctype = "multipart-form-data" method = "post">
File: <input name = "attachment" type = "file" /><br />
Analyzer sensitivity in percents: <input type = "text" name = "sensitivity" value = "10" /><br />
<input type = "submit" value = "Analyze" />
</form>
</body>
</html>
and the handler:
class AnomalyDetectorPage(webapp2.RequestHandler):
def post(self):
uploaded_file = self.request.POST.get("attachment");
file_data = uploaded_file.file.read();
I always getting error of this kind:
File "/base/data/home/apps/s~test-ml/1.398533980585659886/main.py", line 207, in post
file_data = uploaded_file.file.read();
AttributeError: 'unicode' object has no attribute 'file'
I understand that python thinks that files are strings, but what I can do with it???
I tried self.request.POST.get("attachment").file.read(), self.request.POST["attachment"].file.read(), self.request.get("attachment").file.read() and self.request.POST.multi["attachment"].file.read() and maybe something else, but I always getting this error.
What I can do to read content of this file?
The enctype attribute value you are using is wrong. The form should be sent over:
multipart/form-data
<html>
<body>
<form action="/anomalydetector" enctype="multipart/form-data" method="post">
File: <input name="attachment" type="file" />
<br />
Analyzer sensitivity in percents: <input type="text" name="sensitivity" value="10" />
<br />
<input type="submit" value="Analyze" />
</form>
</body>
</html>
<form action="/fileupload" enctype="multipart/form-data" method="post">
<label>Title<input name="name"></label>
<label>Author<input name="author"></label>
<label>Year <input name="year"></label>
<label>Link <input name="link"></label>
<input type="file" name="file">
<input type="submit">
</form>
The question is why self.get_uploads() returns nothing,when self.request.get('file') works (or I suggest it works)
class FileUploadHandler(H.Handler,blobstore_handlers.BlobstoreUploadHandler):
def post(self):
name=self.request.get('name')
if name:
logging.error(name)
author=self.request.get('author')
if author:
logging.error(author)
year =self.request.get('year')
if year and year.isdigit():
year=int(year)
f =self.get_uploads('file')#FILE NOT FOUND
#f=self.request.get('file') # WORKS FINE
if not f:
logging.error("FILE NOT FOUND")
self.redirect("/files")
I looked at the sample app but they also use self.request.get('file')
The answer is that you should create upload url for blob.
You need get_uploads()[0] or name.
Simple example on the uploads handler (Compare and make appropriate changes in your code):
<form name="myform" action="{{ upload_url }}" method="post" enctype="multipart/form-data">
<h1>Select an Image</h1>
<input name="file" type="file"><br>
<input type="submit" value="Upload">
</form>
Handler:
class UploadBlobsHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
try:
upload = self.get_uploads()[0]
logging.info(upload)
url = images.get_serving_url(upload)
# Do something with it.
except:
self.redirect('/uploadform/?error', abort=True)
self.redirect('/uploadform/?success&image_url=' + url)
Example on how to use uploads with blobstorrhandlers: gae-image-upload-example
This is a full solution to my problem:
<form action="{{upload_url}}" enctype="multipart/form-data" method="post">
<label>Title<input name="name"></label>
<label>Author<input name="author"></label>
<label>Year <input name="year"></label>
<label>Link <input name="link"></label>
<input type="file" name="file">
<input type="submit">
</form>
where upload_url =blobstore.create_upload_url('/fileupload',max_bytes_per_blob=10*1000*1000)
and the code to process the request is next:
upload=self.get_uploads('file')[0]
I'd like to upload a text file with bottle, and then read it. How can I do this? Below is what I've tried and didn't work.
HTML:
<form action="/load_from_file" method="post">
<div>
Load File: <input type="file" name="file"/>
<input type="submit" value="Submit"/>
</div>
</form>
Bottle route:
#post('/load_from_file')
def load_from_file():
list_file = request.forms.get("file")
print request.files.get("file")
print request.files["file"]
return "how do I get the uploaded file?"
You should add attribute enctype="multipart/form-data" to form tag.