4

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).

Totty.js
  • 15,563
  • 31
  • 103
  • 175

1 Answers1

6

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)
systempuntoout
  • 71,966
  • 47
  • 171
  • 241
  • Thanks! (: but my application is made in flex, and I'm using the fileReference to upload images 1 by 1. The file reference sends a bytearray object. I would only need the code to save the bytearray object (that is the actual image) to datastore. thanks again ;) – Totty.js Nov 03 '10 at 19:09
  • Thanks again! :) And you know how to set up my app.yaml and ServeHandler in order to get my files like this "www.mysite.com/i/photo_key.jpg"? – Totty.js Nov 04 '10 at 00:30
  • (ho visto k sei italiano xD) - Anyway it doesn't work as expected my url is: "http://localhost:8080/i/agt0b3R0eXN3b3JsZHIQCxIJSW1hZ2VCbG9iGIUDDA.jpg" and I just want the "agt0b3R0eXN3b3JsZHIQCxIJSW1hZ2VCbG9iGIUDDA" part, that is the photo._key | and '/i/(\d+)\.jpg' doesn't work.. – Totty.js Nov 04 '10 at 16:18
  • Just make it to work!the changes: r'/i/(.*)\.jpg' | and then: db.get(self.request.get(photo_id)) -> db.get(db.Key(photo_id)) Thanks!!! – Totty.js Nov 04 '10 at 16:50