I'm trying to do a simple echo app using Python. I want to submit a file with a POST form and echo it back (an HTML file).
Here's the handlers section of the YAML I'm using:
handlers:
- url: /statics
static_dir: statics
- url: .*
script: main.py
It's basically the hello world example in main.py and I added a directory to host my static html form file. Here's the HTML in statics/test.html:
<form action="/" enctype="multipart/form-data" method="post">
<input type="file" name="bookmarks_file">
<input type="submit" value="Upload">
</form>
The handler looks like this:
#!/usr/bin/env python
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
class MainHandler(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write(self.request.get('bookmarks_file'))
def main():
application = webapp.WSGIApplication([('/', MainHandler)],
debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
However, I'm getting an error 405 when posting the file. How come?
You are submitting your form with the POST method, but you implemented a get() handler instead of a post() handler. Changing def get(self): to def post(self): should fix the HTTP 405 error.
Related
I'm trying to get a simple web form up and running that only asks for a URL.
This is the HTML Code (index.html)
<!DOCTYPE html>
<html>
<body>
<form name = 'test' action = "." method = "post">
<form action="test.php" method="get">
URL <input type="text" link="link" name = "URL"/>
<input type="submit" />
</form>
</body>
</html>
I'm using Flask to run the simple web application this is the Flask Code: (app.py)
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/")
def index():
return render_template('index.html')
#app.route("/", methods = ["POST"])
def get_value():
url = request.form["URL"]
return 'The url is ' + url
if __name__ == "__main__":
app.run(debug=True)
and I'm trying to get the inputted URL to another python script so I can do something with it, this is the other python script: (url.py)
from app import get_value
print(get_value())
However, whenever I run python3 url.py it gives me this error:
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
Any idea how to print get the URL over successfully? In a lot of detail preferably because I am very new to Flask.
The error occurs because you called a function that needs data from a request to get the user inputs. You should call the url handling function instead letting the handling function call the retrieval of the url.
Consider this answer https://stackoverflow.com/a/11566296/5368402 to make sure you pass the url correctly. Now that you have your url, simply pass it to your other script.
import url # your url.py module
#app.route("/", methods = ["POST"])
def get_value():
input_url = request.form["URL"]
url.handle_url(input_url) #call a function inside url.py
I'm using this link as an example to uploading images:
https://gist.github.com/jdstanhope/5079277
My HTML code:
<form action="/upload_image" method="post" id="form1" runat="server">
<div class="fileButtons">
<input type='file' id="imgInp" name="imgInput" accept="image/*"/><br><br>
<input type='button' id='remove' value='Remove' />
</div></form>
main.py:
class SetImage(webapp2.RequestHandler):
def post(self):
logging.debug("test")
id = str(self.request.get('id'))
image = self.request.get('imgInput')
app = webapp2.WSGIApplication([('/upload_image', SetImage),
('/', MainPage)], debug=True)
But when I add an image, nothing is being done, and the log console doesn't print:
logging.debug("test")
The recommended way of uploading images to GAE is by using blobstore.
Here is a quick breakdown of the doc to help you achieve this fast:
Imports:
import os
import urllib
import webapp2
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
Serve the form HTML. this form performs the POST to GAE with the selected files data:
class MainHandler(webapp2.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload')
self.response.out.write('<html><body>')
self.response.out.write('<form action="%s" method="POST"
enctype="multipart/form-data">' % upload_url)
self.response.out.write("""Upload File:
<input type="file" name="file"><br> <input type="submit"
name="submit" value="Submit"> </form></body></html>""")
Add a handler for receiving the POST data (binary content of the file). the last line in this function is to redirect the response to the location from where the file could be downloaded:
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
# 'file' is file upload field in the form
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
Add handler to serve the image that you uploaded using the UploadHandler described above:
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
resource = str(urllib.unquote(resource))
blob_info = blobstore.BlobInfo.get(resource)
self.send_blob(blob_info)
And finally, define the routes for the app:
app = webapp2.WSGIApplication([('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler)],
debug=True)
Regarding the issue of your log statement not firing: The default log level for dev_appserver.py is info, which you can override with the --dev_appserver_log_level flag.
Reference the new dev_appserver documentation.
To access uploaded files from a multipart/form-data POST request, the webapp2 documentation states that they're available in request.POST.
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)
How do I write an app.yaml file for a particular Python app I'm trying to put on Google App Engine?
Here is the simple python code I'm trying to work on:
import webapp2
form="""
<form action="http://www.google.com/search">
<input name="q">
<input type="submit">
</form>
"""
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.out.write(form)
app=webapp2.WSGIApplication([('/',MainPage)],
debug=True)
Now whenever I'm trying to run it on Google App Engine, it simply doesn't work. Shows nothing on localhost and shows server error while deploying it.
Here is the app.yaml code:
application: saaps-2012
version: 1
runtime: python
api_version: 1
handlers:
- url: /.*
script: program.py
Try to add the following lines in the end of your file program.py:
def main():
app.run()
if __name__ == "__main__":
main()
Your file should then look like something like this:
import webapp2
form="""
<form action="http://www.google.com/search">
<input name="q">
<input type="submit">
</form>
"""
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.out.write(form)
app=webapp2.WSGIApplication([('/',MainPage)],
debug=True)
def main():
app.run()
if __name__ == "__main__":
main()
Have a try and let me know about your results.
Is it possible to create a textbox in HTML, type a string into it, click a "save" button, store that information onto a GAE datastore model and have the text stay displayed in the textbox and saved in the datastore?
The HTML is on a separate file, just rendered through my main.py file using
class MainPage(webapp.RequestHandler):
def get(self):
template_values = {}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
What I tried for my problem is this:
class equipmentBox(db.Model):
equipCode = db.StringProperty()
class equipmentBoxGet(webapp.RequestHandler):
def post(self):
I think this will help, i have modified default guestbook app for you. Usual way of doing is having html files separately and using templates to render it. Here everything is just embedded into the controller itself
import cgi
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
class EquipmentBox(db.Model):
equipCode = db.StringProperty()
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
equips = db.GqlQuery("SELECT * FROM EquipmentBox")
for equip in equips:
self.response.out.write('<blockquote>%s</blockquote>' %
cgi.escape(equip.equipCode))
# Write the submission form and the footer of the page
self.response.out.write("""
<form action="/post" method="post">
<div><input type="text" name="equip_code" /></div>
<div><input type="submit" value="post equipcode"></div>
</form>
</body>
</html>""")
class EquipBox(webapp.RequestHandler):
def post(self):
equip = EquipmentBox()
equip.equipCode = self.request.get('equip_code')
equip.put()
self.redirect('/')
application = webapp.WSGIApplication(
[('/', MainPage),
('/post', EquipBox)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
The best way to build this sort of interface, where the user "saves" data on the page without the page changing, is to use AJAX calls.
While a full explanation of how AJAX works is probably beyond the scope of an answer here, the basic idea is that you have a Javascript onclick event attached to your Save button, which sends the contents of your textbox via a POST request to the server. See the link above for a tutorial.