Python app engine: how to save a image? - python

This is what I got from flex 4 file reference upload:
self.request =
Request: POST /UPLOAD
Accept: text/*
Cache-Control: no-cache
Connection: Keep-Alive
Content-Length: 51386
Content-Type: multipart/form-data; boundary=----------ei4cH2gL6ae0ei4ae0gL6GI3KM7ei4
Host: localhost:8080
User-Agent: Shockwave Flash
------------ei4cH2gL6ae0ei4ae0gL6GI3KM7ei4
Content-Disposition: form-data; name="Filename"
36823_117825034935819_100001249682611_118718_676534_n.jpg
------------ei4cH2gL6ae0ei4ae0gL6GI3KM7ei4
Content-Disposition: form-data; name="Filedata"; filename="36823_117825034935819_100001249682611_118718_676534_n.jpg"
Content-Type: application/octet-stream
���� [AND OTHER STRANGE CHARACTERS]
My class:
class Upload(webapp.RequestHandler):
def post(self):
content = self.request.get("Filedata")
return "done!"
Now what I'm missing in the Upload class in order to save that file to disk?
i have in the content var some strange characters (viewing in debug).

An App Engine application cannot:
write to the filesystem. Applications must use the App Engine
datastore for storing persistent data.
What you need to do is presenting a form with a file upload field to the user.
When the form is submitted, the file is uploaded and the Blobstore creates a blob from the file's contents and returns a blob key useful to retrieve and serve the blob later.
The maximum object size permitted is 2 gigabytes.
Here is a working snippet that you can try as is:
#!/usr/bin/env python
#
import os
import urllib
from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
class MainHandler(webapp.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>""")
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
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)
def main():
application = webapp.WSGIApplication(
[('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler),
], debug=True)
run_wsgi_app(application)
if __name__ == '__main__':
main()
EDIT1:
in your specific case you could use a BlobProperty (limited to 1MB) to store your request:
class Photo(db.Model):
imageblob = db.BlobProperty()
then adapt your webapp.RequestHandler to save your request:
class Upload(webapp.RequestHandler):
def post(self):
image = self.request.get("Filedata")
photo = Photo()
photo.imageblob = db.Blob(image)
photo.put()
EDIT2:
You don't need to change your app.yaml, just add a new handler and map it in your WSGI.
To retrieve the stored photo you should add another handler to serve your photos:
class DownloadImage(webapp.RequestHandler):
def get(self):
photo= db.get(self.request.get("photo_id"))
if photo:
self.response.headers['Content-Type'] = "image/jpeg"
self.response.out.write(photo.imageblob)
else:
self.response.out.write("Image not available")
then map your new DownloadImage class:
application = webapp.WSGIApplication([
...
('/i', DownloadImage),
...
], debug=True)
You would be able to get images with a url like:
yourapp/i?photo_id = photo_key
As requested, if for any odd reason you really want to serve your images using this kind of url www.mysite.com/i/photo_key.jpg , you may want to try with this:
class Download(webapp.RequestHandler):
def get(self, photo_id):
photo= db.get(db.Key(photo_id))
if photo:
self.response.headers['Content-Type'] = "image/jpeg"
self.response.out.write(photo.imageblob)
else:
self.response.out.write("Image not available")
with a slightly different mapping:
application = webapp.WSGIApplication([
...
('/i/(\d+)\.jpg', DownloadImage),
...
], debug=True)

Related

Non ascii filename in blobstore (Google App Engine)

I am trying to upload some picture to Google App Engine using the Blobstore.
And some of the files contain non-ascii characters.
When I download these files, the filename for these downloaded file appeared to show the "key" in blobstore, rather than the original file name.
My site is http://wlhunaglearn.appspot.com/
I already add a save_as=blob_info.filename in my BlobstoreDownloadHandler , but it failed when the file name contains non-ascii characters.
Any suggestions?
Thanks in advance.
The following is my main.py file
# -*- encoding: utf-8 -*-
import os
import urllib
import webapp2
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
class MainHandler(webapp2.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload')
self.response.out.write('<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><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" multiple name="file"><br> <input type="submit"
name="submit" value="Submit"> </form></body></html>""")
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
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, save_as=blob_info.filename)
app = webapp2.WSGIApplication([('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler)],
debug=True)
Searching all the posts, I finally got a hint from an Answer to another Question
I figure out the correct way to display non-ascii file name is to
add a urllib.quote function to the last line of ServeHandler class
Therefore the ServeHandler class will be:
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, save_as=urllib.quote(blob_info.filename.encode('utf-8')))

GCS upload is realy slow from GAE

I have setup a simple python project on GAE, the user picks a file and it uploads into Google Cloud Storage. This all works fine, but I am getting an upload time of 10-11 seconds when I am uploading a 100kb file. How can I reduce this?
Extra info:
I have a 100Mbis upload speed and the result is the same with a 4kb image, the latency of the first post id about 6 seconds
import os
import urllib
import webapp2
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
class MainHandler(webapp2.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload', gs_bucket_name='bucket_name')
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>""")
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
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)
app = webapp2.WSGIApplication([('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler)],
debug=True)

Why upload handler not match when using GAE blobstore

I just follow GAE's document (https://developers.google.com/appengine/docs/python/blobstore/#Python_Uploading_a_blob) to write upload handler to upload blobstore, when I select one file on computer and click Submit button on HTML page, it will show 'The url "/upload" does not match any handlers.'
Any comments is appreciated.
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
upload_url = blobstore.create_upload_url('/upload')
logging.info(upload_url)
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>""")
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
logging.info('Upload handler')
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
logging.info(upload_files)
self.redirect('/serve/%s' % blob_info.key())
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
resource = str(urllib.unquote(resource))
logging.info(resource)
blob_info = blobstore.BlobInfo.get(resource)
self.send_blob(blob_info)
application = webapp2.WSGIApplication([
('/', MainPage),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler),
], debug=True)
[Update1]
After I click submit button, I check dev-server Blobstore Viewer, I found the file has been uploaded there, however, my chrome browser still show 'The url "/upload" does not match any handlers.'. This is why?
I want to ask my question by self that maybe someone encounter similar issue as me.
After I change from
- url: /
script: AppWS.application
to
- url: (/.*)*
script: AppWS.application
everything is OK.

Uploading images - Google App Engine + Python

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.

Uploading a video to google app engine blobstore

I'm trying to associate a video file to a record with a bunch of properties, but can't seem to allow the user to do everything in one form - name the video, provide description and answer some question, AND upload the file.
Here are the steps I'd like to perform:
User is served with a page containing a form with the following fields: Name, Description, File selector.
The file gets stored as a blob and the id gets recorded together with name and description.
Does anyone have any examples of doing this I could learn from or a tutorial you could point me to? The one from google only shows uploading the file and getting redirected to it.
Thanks and sorry for a newbish question!
http://demofileuploadgae.appspot.com/ - My demo uploader to the blobstore.
My code for the upload: http://code.google.com/p/gwt-examples/source/browse/trunk/DemoUpload/src/org/gonevertical/upload/#upload/server%3Fstate%3Dclosed
Here's the code I'm using to upload images and associate them with articles. The toughest bit was getting the article id to get to the upload handler, I solved it by setting the file name as the article id to get around the problem.
from lib import urllib2_file
from lib.urllib2_file import UploadFile
# this view serves a task in a queue
def article(request):
article = Article.objects.get(id=form.cleaned_data['article'])
try:
image = StringIO(urllib2.urlopen(image_url).read())
except (urllib2.HTTPError, DownloadError):
article.parsed = True
article.save()
else:
image = UploadFile(image, '.'.join([str(article.id), image_url.rsplit('.', 1)[1][:4]]))
upload_url = blobstore.create_upload_url(reverse('Articles.views.upload'))
try:
urllib2.urlopen(upload_url, {'file': image})
except (DownloadError, RequestTooLargeError):
pass
return HttpResponse(json.dumps({'status': 'OK'}))
def upload(request):
if request.method == 'POST':
blobs = get_uploads(request, field_name='file', populate_post=True)
article = Article.objects.get(id=int(blobs[0].filename.split('.')[0]))
article.media = blobs[0].filename
article.parsed = True
article.save()
return HttpResponseRedirect(reverse('Articles.views.upload'))
else:
return HttpResponse('meow')
def upload(request):
if request.method == 'POST':
blobs = get_uploads(request, field_name='file', populate_post=True)
article = Article.objects.get(id=int(blobs[0].filename.split('.')[0]))
article.media = blobs[0].filename
article.parsed = True
article.save()
return HttpResponseRedirect(reverse('Articles.views.upload'))
else:
return HttpResponse('meow')
# this serves the image
def image(request):
blob = BlobInfo.gql("WHERE filename='%s' LIMIT 1" % request.form.cleaned_data['id'])[0]
return HttpResponse(BlobReader(blob.key()).read(),
content_type=blob.content_type)
Also you'll need this http://fabien.seisen.org/python/urllib2_file/
Here is how I did it. It is more straight forward than you think. Note the following taken from Blobstore overview.
"When the Blobstore rewrites the user's request, the MIME parts of the uploaded files have their bodies emptied, and the blob key is added as a MIME part header. All other form fields and parts are preserved and passed to the upload handler." In the upload handler is where you can do whatever it is you want with the other form fields.
class Topic(db.Model):
title = db.StringProperty(multiline=False)
blob = blobstore.BlobReferenceProperty()
imageurl = db.LinkProperty()
class MainHandler(webapp.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>
<div><label>Title:</label></div>
<div><textarea name="title" rows="1" cols="25"></textarea></div><input type="submit"
name="submit" value="Submit"> </form>""")
self.response.out.write('<br><br><h2>TOPIC LIST</h2><table border="1"><tr><td>')
for topic in Topic.all():
self.response.out.write('<div><img src="%s=s48"/>' % topic.imageurl)
self.response.out.write('<div><b>Image URL: </b><i>%s</i></div>' % topic.imageurl)
self.response.out.write('<div><b>Title: </b><i>%s</i></div>' % topic.title)
self.response.out.write('</td></tr></table><br>')
self.response.out.write('</body></html>')
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
topic = Topic()
topic.title = self.request.get("title")
topic.blob = blob_info.key()
topic.imageurl = images.get_serving_url(str(blob_info.key()))
topic.put()
self.redirect('/')
def main():
application = webapp.WSGIApplication(
[('/', MainHandler),
('/upload', UploadHandler),
], debug=True)
run_wsgi_app(application)

Categories