I'm learning python with book "Learn python the hard way"
I'm doing the web exercise, but I can't find a concrete information.
import web
urls =( '/hello', 'Index')
app = web.application(urls,globals())
render = web.template.render(<mypath>)
class Index(object):
def GET(self):
return render.hello_form()
def POST(self):
form = web.input(name="Nobody", greet="Hello")
greeting = "%s, %s" %(form.greet, form.name)
return render.index(greeting = greeting)
then... in my "hello_form"
<form action="/hello" method="POST">
A greeting <input type=text" name="greet">
<br/>
Your Name: <input type="text" name="name">
<br/>
<input type="submit>
</form>
well, I can't access to the action="/hello".
but I can access with action="/" well I don't know which is the reason
Someone could explain me?
when you run you app.py bu default you are directed here:
http://0.0.0.0:8080/
But it says to you "File Not Found" because you have to go here:
http://0.0.0.0:8080/hello
So either you change your app.py keeping only / in your urls
either you add manually /hello in your URL.
Cheers,
Filiberto
Related
I'm completely new to flask, and really am completely lost with how to approach this. I've looked into other SO questions but I can't seem to get this working regardless.
I have a form as such:
<form class="teamSelection" method="POST" action="/submitted">
<select class="teamForm" id="teamDropdownSelector" type="text" name="teamDropdown" placeholder="Select A Team">
<option disabled selected>Select a game</option>
<option id="WatfordVSManchester Utd" value="">Watford VS Manchester Utd</option>
</select>
<input class="btn" type="submit" value="submit">
</form>
and my flask as so:
from flask import Flask
app = Flask(__name__)
#app.route("/submitted")
def hello():
return "hello world"
The goal is to take the content of the selected/submitted dropdown item, pass this to the flask file where I then use the team names to scrape information about the match. However at the moment I can't even seem to get the POST of the form to work and am at a complete loss. I appreciate this is a pretty vague and open-ended question, but I seriously don't know how else to figure this out.
Should I instead use jquery to detect when the dropdown has changed and use AJAX to send a POST to somehow call the script and pass the values into it?
Any help would be greatly appreciated.
EDIT
I thought I put this in the original post, but must have forgot.
I am currently running an apache localhost server, and am working with flask via pycharm. All I've done at the moment is install the flask package in pycharm, and haven't set any of it up like I've seen in some tutorials do when running from the command line. I assumed this step wasn't necessary, as I already have a server up and running with apache?
When it comes to backend stuff like this I really have no idea, so apologies if that's a stupid assumption.
I've changed the flask to:
from flask import Flask
app = Flask(__name__)
#app.route("/submitted", methods=['POST'])
def hello():
with open("newTest.csv", mode="w+") as file:
fileWriter = csv.writer(file)
fileWriter.writerow(['Time', 'HomeTeam', 'AwayTeam'])
file.close()
The reason being as I can see if this script is actually being called, if it is it will make a new csv file called newTest. After running the webpage and submitting no new csv file appears, so this script isn't being run, meaning it's likely due to me not configuring flask correctly?/The assumption that apache was enough was incorrect?
You have just to tell the flask method to accept POST request and to read parameters from the request
Example:
from flask import Flask, request
app = Flask(__name__)
#app.route("/submitted", methods=['POST'])
def hello():
myvariable = request.form.get("teamDropdown")
... your code ...
return "hello world"
So, your question is not about flask, but about fopen - you have to add a full file path including directory path script_dir = path.dirname(path.abspath(__file__)).
Flask script (modified for launching in my local copy of project):
from flask import Flask, render_template, request
import csv
from os import path
app = Flask(__name__)
script_dir = path.dirname(path.abspath(__file__))
#app.route ("/")
def index():
return render_template("index.html")
#app.route("/submitted", methods=["GET", "POST"])
def hello():
if request.method == "GET":
return render_template("index.html")
filefullpath = script_dir + '//newTest.csv'
with open(filefullpath, mode="w+") as file:
fileWriter = csv.writer(file)
fileWriter.writerow(['Time', 'HomeTeam', 'AwayTeam'])
file.close()
return "hello world"
index.html (in folder "/templates")
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
Test
<br>
<form class="teamSelection" method="POST" action="/submitted">
<select class="teamForm" id="teamDropdownSelector" type="text" name="teamDropdown" placeholder="Select A Team">
<option disabled selected>Select a game</option>
<option id="WatfordVSManchester Utd" value="">Watford VS Manchester Utd</option>
</select>
<input class="btn" type="submit" value="submit">
</form>
</body>
</html>
Modify your code as:
from flask import Flask
app = Flask(__name__)
#app.route("/submitted", methods=['POST'])
def hello():
return request.form['teamDropdown']
Please let me know if that helps.
I have the following form shown in a modal of a bootstrap page
the aim is to upload a file with a hidden id
the application is based on Google App Engine, Python/Webapp2
<form action="someUrl" role="form" method="POST" enctype="multipart/form-data">
<input type="hidden" name="entityId" value="{{datastoreEntity.key.id()}}"/>
<input name="importFile" type="file" multiple>
<input type="text" class="form-control" readonly>
<input type="submit" name="submit" value="Import">
</form>
the problem is in the related RequestHandler (server side) where I can retrieve the file with
raw_file = self.request.POST.multi['importFile'].file
But I can't get the id (which is correctly generated by Jinja2 - checked in the page source). I have already tried with
self.request.get('entityId')
self.request.POST['entityId']
self.request.POST.multi['entityId']
I can't reproduce the problem as you relate it in the simplest of ways. I've copied that template into form.html, direct / to MainHandler, and net of the usual preparations (imports, jinja_environment with a FileLoader in the current dir, etc, I have):
class It(ndb.Model):
name = ndb.StringProperty()
class MainHandler(webapp2.RequestHandler):
def get(self):
dse = It(name="Willy")
dsek = dse.put()
datastoreEntity = dsek.get()
template = jinja_environment.get_template('form.html')
self.response.write(template.render(dict(
datastoreEntity=datastoreEntity,
)))
def post(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.write(self.request.get('entityId'))
Visiting /, picking a file, and clicking the Import button, I see on my browser: 5066549580791808 -- which seems to be a typical datastore entity ID, as desired.
Please "interpolate" between this toy super-simplified version, and the no doubt much more complex things you're trying to do, and edit your Q to show us the very simplest way you can reproduce your problem, thanks!
Uploading via file inputs in App Engine requires that the app use a path that's obtained from the blobstore API. The doc for that is here. So you probably want to do something like
upload_url = blobstore.create_upload_url('/someUrl')
and then inject that into your template so that the form can use it
<form action="{{upload_url}}" ...
Once the file upload is complete, blobstore will redirect to /someUrl, where you process the rest of the form, including .file.
I have an HTML form that allows file uploads. I need to send the uploaded file via email. I am following the Google appengine Request class example.
from google.appengine.ext import webapp
from google.appengine.api import mail
class MyRequestHandler(webapp.RequestHandler):
def get(self):
self.response.out.write('''
<html>
<body>
<form method="post">
<p>File: <input type="file" name="upload" /></p>
<p><input type="submit" /></p>
</form>
</body>
</html>
''')
def post(self):
uploaded_file = self.request.get("upload")
uploaded_name = "file.doc"
message = mail.EmailMessage(sender="Me <me#mydomain.com>",
subject="Email from me")
message.to = "Me <me#mydomain.com>"
message.body = "See attached file."
message.attachments = [(uploaded_name, uploaded_file)]
message.send()
The above code works. I need to replace the hardcoded file name (file.doc) in the message.attachments tuple with the actual name of the file uploaded. I have two questions:
How do I get the uploaded file name from the webapp Request class?
Where can I find the documentation that describes how to do this? I have done a bunch of searching and can not find reference material or examples.
UPDATE:
Looks like the solution is:
if uploaded_file != "":
uploaded_name = self.request.params["upload"].filename
...as posted
here.
Instead of going self.request.get("upload"), try examining the self.request.POST["upload"] dict.
Specifically, self.request.POST['upload'] will return a cgi.FieldStorage instance. The attribute you are looking for is filename. Also of interest would be mimetype - and of course data.
For a complete how-to on handling uploads, take a look at this ancient post over at Nick Johnson's blog.
For an under-the-hood look at how webapp2 request data works, consult this portion of webapp2 docs.
I am trying to read and print a file in Google App Engine, but the code bellow seems unresponsive. I can upload the file, and my expectation was that it would just print the text, but it does nothing. I thought about adding a submit button, but I have no idea how to link submit with pythons printing. How can I get this to print on command?
I have seen the example provided by GAE here, but I would first like to keep it all on one page, and second I still don't understand how the submit calls that second page.
import webapp2
from google.appengine.ext.webapp import util
class MainPage(webapp2.RequestHandler):
#http://bukhantsov.org/2011/12/python-google-app-engine-calculator/
def get(self):
# build a list of operations
self.response.out.write("""<html>
<body>
<form action='/' method='get' autocomplete='off'>
<input type='file' name='file'/><br/>
#<input type='submit' name="test" value="submit">
</form>
</body>
</html>""")
file = self.request.get('file')
self.response.out.write(file)
app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
def main():
util.run_wsgi_app(app)
if __name__ == '__main__':
main()
Your form is sent using the HTTP GET method, but for file uploads you need POST. Change it from:
method='get'
to:
method='post'
You will also need to handle POST requests in a different method. The POST body itself should be available as self.request.POST. So you end up with something like:
def post(self):
file = self.request.POST['file']
self.response.out.write(file)
Im trying to make a form where users can upload a file. And I have a form that takes the users arguments and posts them to the UploadHandler that is mapped to the url that is passed as parameter to the renderfunction. It works up to the point that it renders the form, but when submitting the file it redirects me to a blank page and the console shows me the error:
ERROR 2013-03-17 11:53:30,769 dev_appserver_blobstore.py:404] Could not find session for ahhkZXZ-a3Vyc3NhbW1hbmZhdHRuaW5nYXJyGwsSFV9fQmxvYlVwbG9hZFNlc3Npb25fXxgxDA
INFO 2013-03-17 11:53:30,779 dev_appserver.py:3104] "POST /_ah/upload/ahhkZXZ- a3Vyc3NhbW1hbmZhdHRuaW5nYXJyGwsSFV9fQmxvYlVwbG9hZFNlc3Npb25fXxgxDA HTTP/1.1" 404 -
Im still new at this but I can't seem to find whats going on. I understand that the mappings somehow f***s up, but still I don't understand why it doesn't redirect me to the correct handler (SummaryHandler)?
The class that serves the form for file upload:
class CreateHandler(BaseHandler):
def get(self):
self.render('create.html', upload_url = blobstore.create_upload_url('/upload'))
The html-form ('create.html'):
<h2 class="main-title">Upload a file!</h2>
<form action="{{upload_url}}" method="post" enctype="multipart/form-data">
<label>
<div>Upload:</div>
<input type="file" name="file" accept="application/pdf"><br>
</label>
<div class="error">
{{file_error}}
</div>
<br>
<input type="submit" name="submit" value="Submit">
</form>
The uploadhandler that takes the form args:
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
#validation of form-vars
have_error=False
file_data=dict()
if not (blob_info.content_type == 'application/pdf'):
file_data['file_error']="You can only upload files in pdf-format."
have_error=True
if have_error:
self.render('create.html', **file_data)
else:
#'parent' is just some stuff for organising the database.
#Not important in this context
the_file = A_File(parent = summary_key(),
file_key=str(blob_info.key()))
the_file.put()
if the_file:
self.redirect('/summary/%s' % str(the_file.key().id()))
else:
_error="Could not find the file"
self.render('welcome.html', error=_error)
The application handlers and their mappings:
app = webapp2.WSGIApplication([
(r'/', WelcomeHandler),
(r'/create', CreateHandler),
(r'/upload', UploadHandler),
(r'/summary/(\d+)', SummaryHandler) #I have not included this handler in the text
], debug=True)
It might be the fact that this session expired or it was used. The urls that created using create_upload_url have an expiration (I think 10 min). Before actually posting you might want to refresh that URL using JavaScript.
Also if for any reason the file was uploaded in the Blobstore you won't be able to use the same URL again, it is only good for one request (could have multiple files though).
In your example, try to remove all the file specific checks, try to upload something and check through the administrative console in the Datastore Viewer if you have any blobs or session keys. This can be accessed through this URL:
http://localhost:8080/_ah/admin/datastore