Google App Engine (Python) - Uploading a file (image)
Asked Answered
T

3

7

I want the user to be able to upload images to Google App Engine. I have the following (Python):

class ImageData(ndb.Model):
     name = ndb.StringProperty(indexed=False)
     image = ndb.BlobProperty()

Information is submitted by the user using a form (HTML):

<form name = "input" action = "/register" method = "post">
    name: <input type = "text" name = "name">
    image: <input type = "file" name = "image">
</form>

Which is then processed by:

class AddProduct(webapp2.RequestHandler):
    def post(self):
        imagedata = ImageData(parent=image_key(image_name))
        imagedata.name = self.request.get('name')
        imagedata.image = self.request.get('image')
        imagedata.put()

However, when I try to upload an image, lets say "Book.png", I get the error: BadValueError: Expected str, got u'Book.png'

Any idea what is going on? I have been working with GAE for quite some time, but this is the first time I had to use blobs.

I used this link: https://developers.google.com/appengine/docs/python/images/usingimages which uses db, not ndb. I also tried storing the image in a variable first like in the link: storedInfo = self.request.get('image') and then storing it: imagedata.image = ndb.Blob(storedInfo) Which ALSO gives me an error: AttributeError: 'module' object has no attribute 'Blob' Thanks in advance.

Tokoloshe answered 23/8, 2013 at 0:19 Comment(6)
The error is telling you that you're trying to set a Unicode object as the value of a blob, which in this case seems to be the file name, not the file data itself. (I'm not sure how to get the raw data as an str in webapp2, so just posting as a comment)Sprain
any reason you are not using the blobstore api than datastore? developers.google.com/appengine/docs/python/blobstore/…Saponify
Thank you Wooble, but what would you suggest I do? And Faisal, I am not using it because it needs db (I am using ndb) and webapp (I am using webapp2).Tokoloshe
I don't use webapp2 (or webapp for that matter) but a cursory examination of the documentation shows that you are doing it wrong. An uploaded file will normally be accessed through a cgi.FieldStorage obejct - see the docs webapp-improved.appspot.com/guide/request.html . In addition you may need to set the encoding normally to something like multipart/form-data See docs - w3.org/TR/html401/interact/forms.html#h-17.13.4Lammergeier
Thanks a lot for the links guys. Finally figured it out, I found an example about using blobs and studied how it works, then incorporated that into my code. Again, thanks everyone.Tokoloshe
Could you put a link to that example so others, who have the same problem, get it done?Monk
T
9

Had the same prob.

just replace

imagedata.image = self.request.get('image')

with:

imagedata.image = str(self.request.get('image'))

also your form needs to have enctype="multipart/form-data

<form name = "input" action = "/register" method = "post" enctype="multipart/form-data">
Teenateenage answered 28/5, 2014 at 3:21 Comment(0)
V
5

There is a great example in the documentation that describes how to upload files to the Blobstore using a HTML form: https://developers.google.com/appengine/docs/python/blobstore/#Python_Uploading_a_blob

The form should point to a url generated by blobstore.create_upload_url('/foo') and there should be a subclass of the BlobstoreUploadHandler at /foo like this:

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
  def post(self):
    upload_files = self.get_uploads('file')
    blob_info = upload_files[0]
    imagedata = ImageData(parent=image_key(image_name))
    imagedata.name = self.request.get('name')
    imagedata.image = blob_info.key()
    imagedata.put()

For this to work, you should change your data model such that in ImageData, image referes to a ndb.BlobKeyProperty().

You can serve your image simply from a url generated by images.get_serving_url(imagedata.image), optionally resized and cropped.

Vail answered 9/10, 2013 at 16:49 Comment(1)
I think this only works with python 2.7 - I'm now looking for a python 3.7 equivalent. It seems straightforward to get a browser to post to app engine then write that to cloud storage, but being able to get the user to post directly to cloud storage isn't something I've found documentation for as yet.Astute
G
3

You must add enctype="multipart/form-data" to your form in order for this to work

<form name = "input" action = "/register" method = "post" enctype="multipart/form-data">
    name: <input type = "text" name = "name">
    image: <input type = "file" name = "image">
</form>
Gloriane answered 20/9, 2013 at 14:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.