my blobstore_image model: db.define_table('blobstore_image', db.version_info, Field('blob_key', 'upload', notnull=True, requires=IS_LENGTH(1048576), represent=lambda image : A('download', _href=URL( r=request, c='gae_blobstore', f='download', args=[image])), label="Image"), Field('image_url', length=500), Field('name', length=128, requires=IS_NOT_IN_DB(db, 'blobstore_image.name')), Field('type', length=128, requires=IS_IN_SET(['i_classify', 'my_images', 'by_type'], zero=None)), migrate=True)
my upload controller: def upload_image(): """ This is the integration of the GAE blobstore with the image upload process @TODO: figure out how to test this. image upload is going to be kinda difficult to spoof """ #@TODO: how do we deal with deleting an image? logging.info(repr(request.post_vars)) fields=['name', 'type', 'blob_key'] form = SQLFORM(db.blobstore_image, fields=fields, formstyle='divs') if request.args and request.args[0]: form = SQLFORM(db.blobstore_image, request.args[0], fields=fields, upload=URL(r=request, c='gae_blobstore', f='preview'), formstyle='divs') if request.env.web2py_runtime_gae: from google.appengine.ext import blobstore from google.appengine.api.images import get_serving_url import uuid #get the blob_info. NOTE this MUST be done before any other operations on # the request vars. otherwise something modifies them (perhaps the form # validators) in a way that makes this not work blob_info = None if request.vars.blob_key == '': #it seems that prod blobstore returns empty string instead of None when #there are no changes to the image request.vars.blob_key = None if request.vars.blob_key != None: blob_info = blobstore.parse_blob_info(request.vars.blob_key) del request.vars['blob_key'] upload_url = blobstore.create_upload_url(URL(r=request,f='upload_image', args=request.args, vars={'redir':URL(r=request,c='dataadmin', f='index')})) form['_action']=upload_url #since we are setting the action after the form was initially created we # need to reset the form.custom.begin (begin, end) = form._xml() form.custom.begin = XML("<%s %s>" % (form.tag, begin)) if form.accepts(request.vars,session, formname="uploadimage"): #@TODO: can this be a post-validation function? #get the record we just inserted/modified row = db(db.blobstore_image.id == form.vars.id).select().first() if request.vars.blob_key__delete == 'on' or \ (blob_info and (row and row.blob_key)): #remove from blobstore because of delete or update of image decoded_key = base64.b64decode(row.blob_key.split('.')[0]) blobstore.delete(decoded_key) #remove reference in the artwork record row.update_record(blob_key=None) if blob_info: logging.info("adding blob_key " + str(blob_info.key())) #add reference to image in this record key = base64.b64encode(str(blob_info.key())) +"." + blob_info.content_type.split('/')[1] url = get_serving_url(str(blob_info.key())) row.update_record(blob_key = key, image_url = url) crud.archive(form) session.flash="Image saved" #Raise the HTTP exception so that the response content stays empty. #calling redirect puts content in the body which fails the blob upload raise HTTP(303, Location= URL(r=request,f='upload_image', args=form.vars.id)) elif form.errors: #logging.info("form not accepted") logging.info(form.errors) session.flash=BEAUTIFY(form.errors) #there was an error, let's delete the newly uploaded image if blob_info: blobstore.delete(blob_info.key()) #Raise the HTTP exception so that the response content stays empty. #calling redirect puts content in the body which fails the blob upload redirvars = {} redirvars['form_errors']=True redirvars['error_dict'] = form.errors raise HTTP(303, Location= URL(r=request,f='upload_image', args=request.args, vars=redirvars)) return dict(form=form, aahome=A("data Home", _href=URL(r=request, f='index')), back=A("Query view", _href=URL(r=request, f='query', args=['blobstore_image']))) hope that helps! cfh