Python应用引擎:如何保存图片?

4 投票
1 回答
3782 浏览
提问于 2025-04-16 06:17

这是我从Flex 4的文件引用上传中得到的内容:

我有一个请求:

    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]

我的类:

class Upload(webapp.RequestHandler):
    def post(self):
        content = self.request.get("Filedata")
        return "done!" 

现在我在上传类中缺少什么,才能把那个文件保存到磁盘上呢?我在内容变量中看到一些奇怪的字符(在调试时查看)。

1 个回答

6

一个App Engine应用程序不能:

  • 写入文件系统。应用程序必须使用App Engine的数据存储来保存持久数据。

你需要做的是给用户展示一个带有文件上传字段的表单。
当用户提交表单时,文件会被上传,Blobstore会根据文件内容创建一个“blob”,并返回一个blob键,这个键可以用来后续获取和展示这个blob。
允许的最大对象大小是2GB。

这里有一个可以直接使用的代码片段:

#!/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()

编辑1:
在你的具体情况下,你可以使用BlobProperty(限制为1MB)来保存你的请求:

class Photo(db.Model):
 imageblob = db.BlobProperty()

然后调整你的webapp.RequestHandler来保存你的请求:

class Upload(webapp.RequestHandler):
    def post(self):
        image = self.request.get("Filedata")
        photo = Photo()
        photo.imageblob = db.Blob(image) 
        photo.put()

编辑2:
你不需要修改你的app.yaml,只需添加一个新的处理程序并在你的WSGI中进行映射。要获取存储的照片,你应该添加另一个处理程序来展示你的照片:

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

然后映射你的新DownloadImage类:

application = webapp.WSGIApplication([
    ...
    ('/i', DownloadImage),
    ...
], debug=True)

你可以通过类似这样的URL获取图片:

yourapp/i?photo_id = photo_key

如果你真的想用这种URL格式来展示你的图片,比如www.mysite.com/i/photo_key.jpg,你可以尝试这样做:

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

使用稍微不同的映射:

application = webapp.WSGIApplication([
        ...
        ('/i/(\d+)\.jpg', DownloadImage),
        ...
    ], debug=True)

撰写回答