0
votes

I am using the App Engine python development server 1.9.20 on a Mac.

I've had success with the Blobstore but I'm switching my code to use cloudstore before I launch my site.

I'm not getting any errors in the console. But I'm not getting an image displayed in the browser. The browser displays the "image not found icon". ("?" in Safari.)

I cobbled together my cloud storage code from examples referenced here on SO. Mostly from voscausa's code (ref below).
The serving url looks correct (based what I would expect from the sample documentation).

But no image. If you have any idea what I'm doing wrong, I would be pleased to hear your input.

I'm saving the uploaded image blob key and url to the UserProfile entity.

class UserProfile(ndb.Model):
    profile_image_url = ndb.StringProperty(indexed=False, default=None)
    profile_image_key = ndb.BlobKeyProperty(indexed=False, default=None)

I write to the GCS and generate a blobstore key here:

def CreateFile(filename, upload_file, content_type):
    with gcs.open(filename, 'w',
                  options={b'x-goog-acl': b'public-read'},
                  content_type=content_type) as f:
        f.write(upload_file)
    blobstore_filename = '/gs' + filename
    return blobstore.create_gs_key(blobstore_filename)

My upload handler looks like this:

class UploadHandler(webapp2.RequestHandler):    
    def post(self):
        user = users.get_current_user()
        path = self.request.path
        item = self.request.get('item')
        image_num = self.request.get('image')
        src = self.request.get('src')
        group_id = self.request.get('id')

        if user:
            this_user_qry = UserProfile.query(UserProfile.user_id == user.user_id(), ancestor=user_key(user.user_id()))
            try:
                this_user = this_user_qry.get()
            except:
                logging.error('In UploadHandler, src = profile this_user_qry.get() failed')

        if src == 'profile':
            return_path = '/edit_profile#image'

            #if this_user.profile_image_key != None:

                #''' profile image exists, removing the current image, replaced with this_user.profile_image_key '''
                #blobstore.delete(this_user.profile_image_key)

                #this_user.profile_image_key = None
                #this_user.profile_image_url = None

            bucket_name = os.environ.get('BUCKET_NAME',
                                         app_identity.get_default_gcs_bucket_name())

            file_data = self.request.get("file", default_value=None)
            file_name = self.request.POST["file"].filename
            file_ext = file_name.lower().split('.')[-1]
            gcs_file = "/%s/profile/%s/%s" % (bucket_name, str(user.user_id()), file_name)
            #gcs_file = "/%s/%s" % (bucket_name, file_name)

            mimetypes.init()
            content_type = mimetypes.guess_type(file_name)[0]

            if file_data:
                blob_key = blobstore.BlobKey(CreateFile(gcs_file, file_data, content_type))

                if file_ext in ['png', 'jpg', 'gif']:
                    serving_url = images.get_serving_url(
                        blobstore.create_gs_key('/gs' + gcs_file), secure_url=True)
                elif gae_development:
                    # this SDK feature has not been documented yet !!!
                    serving_url = 'http://localhost:8080/_ah/gcs' + gcs_file
                else:
                    serving_url = 'https://storage.googleapis.com' + gcs_file
                print "\n-new-\nserving_url = %s" % serving_url

                this_user.profile_image_key = blob_key
                this_user.profile_image_url = serving_url
                try:
                    this_user.put()
                except:
                    logging.exception('In UploadHandler, if blob_key, this_user.put()')
                    self.redirect('/upload_image_error')
                else:
                    self.redirect('/edit_profile#image')

The printed values for [gcs_file, blob_key, serving_url] are:

gcs_file = /app_default_bucket/profile/112118202356943244222/MichaelEdland_112514.jpg

blob_key = encoded_gs_file:YXBwX2RlZmF1bHRfYnVja2V0L3Byb2ZpbGUvMTEyMTE4MjAyMzU2OTQzMjQ0MjIyL01pY2hhZWxFZGxhbmRfMTEyNTE0LmpwZw==

serving_url = http://0.0.0.0:8080/_ah/img/encoded_gs_file:YXBwX2RlZmF1bHRfYnVja2V0L3Byb2ZpbGUvMTEyMTE4MjAyMzU2OTQzMjQ0MjIyL01pY2hhZWxFZGxhbmRfMTEyNTE0LmpwZw==

For the Jinja template:

I'm passing this value to the template:

'profile_image_url': this_user.profile_image_url,

And this to display the image on the profile page:

<img border="0" src="{{ profile_image_url | safe }}" width="100%" >

In the App Engine Console Datastore Viewer

Entity Kind Blobinfo has two entries for this one image

Key Names

1) 3kD4IorO9hfg-J7OrZtmVQ==

2) encoded_gs_file:YXBwX2RlZmF1bHRfYnVja2V0L3Byb2ZpbGUvMTEyMTE4MjAyMzU2OTQzMjQ0MjIyL01pY2hhZWxFZGxhbmRfMTEyNTE0LmpwZw==

filenames 1) MichaelEdland_112514.jpg 2) None

sizes

1) 166464 2) 250

There's one entry for BlobServingUrl

key name and blob_key are both:

encoded_gs_file:YXBwX2RlZmF1bHRfYnVja2V0L3Byb2ZpbGUvMTEyMTE4MjAyMzU2OTQzMjQ0MjIyL01pY2hhZWxFZGxhbmRfMTEyNTE0LmpwZw==

GSFileInfo Key Name = encoded_gs_file:YXBwX2RlZmF1bHRfYnVja2V0L3Byb2ZpbGUvMTEyMTE4MjAyMzU2OTQzMjQ0MjIyL01pY2hhZWxFZGxhbmRfMTEyNTE0LmpwZw==

content_type = image/jpeg filename = /app_default_bucket/profile/112118202356943244222/MichaelEdland_112514.jpg

Some things I found helpful (to get to this point):

voscausa's answer was helpful How to serve cloudstorage files using app engine SDK

and his revised code example was helpful https://github.com/voscausa/appengine-gcs-blobstore-python

in the documentation there is an example of what the serving url looks like

I did also read the Google docs, which got me this far. (I can't post the links because of a lack of reputation)

But now I appear to be stuck.

Thanks in advance. After a year of using StackOverflow every day, I finally have to ask a question. :-) Probably 511 (too much information) but I appreciate the help.

1

1 Answers

0
votes

Can you 'wget' the image file to see if it was transferred properly? I.e., check if it was transferred as text or as binary?

This question might be helpful: How to write raw bytes to Google cloud storage with GAE's Python API

Especially this quote from the accepted answer:

I suppose the problem is that gcs_file.write() method expects data of type "str".

In your CreateFile function, the f.write(upload_file) statement might be writing the upload_file incorrectly.