Google App Engine BlobProperty 返回过期内容

1 投票
1 回答
717 浏览
提问于 2025-04-16 19:51

我把缩略图存储在Google App Engine的实体中,使用的是BlobStoreProperties。随着时间的推移,这些缩略图需要更新,我通过用新的图片数据更新这些实体的内容来实现。然而,我发现每次取回这些图片时,仍然得到的是第一次保存的旧版本。这种行为真让人感到意外和困惑。我写了一段简单的独立代码来验证这个问题。

下面是两个简单的处理程序和一个模型定义。SaveImageHandler负责把图片保存到数据库,而LoadImageHandler则用来取回图片。

from google.appengine.ext import db
import logging

class Image(db.Expando):
 data = db.BlobProperty(required=True)
 uid = db.StringProperty(required=True) 

class SaveImageHandler(webapp.RequestHandler):                                
  def post(self, uid):                                                        
    imgdata = self.request.POST.get('imgdata').file.read()                    
    logging.error('Saving %d bytes'%(len(imgdata)))                           
    image = model.Image(data=imgdata, uid=uid)                                
    image.put()                                                               

class LoadImageHandler(webapp.RequestHandler):                                
  def post(self, uid):                                                        
    image = model.Image.gql('WHERE uid = :1', uid).get()                      
    self.response.headers['Content-type'] = 'image/png'                       
    logging.error('Loading %d bytes'%(len(image.data)))                       
    self.response.out.write(image.data)    

def application():
  return webapp.WSGIApplication([
    ('/_thumbsave/(.*)', SaveImageHandler),
    ('/_thumbload/(.*)', LoadImageHandler),
  ],debug=False)

def main():
  util.run_wsgi_app(application())

if __name__ == '__main__':
  main()

我这样上传一张图片

curl -F "imgdata=@/tmp/img1.png" http://ubuntu.local:8000/_thumbsave/X

然后我取回这张图片

curl -d dummy=0 http://ubuntu.local:8000/_thumbload/X > Downloads/imgout.png

imgout.pngimg1.png是一样的

接着我上传另一张图片img2.png

curl -F "imgdata=@/tmp/img2.png" http://ubuntu.local:8000/_thumbsave/X

然后以同样的方式取回它。我期待现在imgout.pngimg2.png是一样的。但结果我发现它仍然是之前的旧图img1.png。因此,图片查询返回了一个过时的对象。日志中打印的图片长度也验证了第二次返回的图片并不是更新后的版本。

这里到底出了什么问题呢?

1 个回答

3

在你的 SaveImageHandler 里,每次你发送图片数据时,都会创建一个新的 Image 实体。然后在 LoadImageHandler 中,你只是获取那个 uid 对应的第一个图片。

你可以把它改成“查找或创建”图片,像这样:

class SaveImageHandler(webapp.RequestHandler):
  def post(self, uid):
    image = Image.all().filter("uid =", uid).get()
    if not image:
        image = model.Image(uid=uid)
    image.data = self.request.POST.get('imgdata').file.read()
    image.put()

与其使用 uid 属性,不如考虑使用 key_names 来达到这个目的,并且可以看看这个 get_or_insert 方法。

撰写回答