如何保存上传的文件然后用GAE返回?

时间:2011-07-27 18:16:57

标签: google-app-engine memcached google-cloud-datastore blobstore

我需要使用GAE使用创建以下应用程序:

  1. 用户上传一些文件(假设将其发送到myapp.appspot.com/upload);
  2. 我需要保存(在数据存储区中?)并返回链接;
  3. 根据提供的链接,用户应该可以在5分钟内下载文件。
  4. 我创建了以下内容:

    的app.yaml

    application: synoext
    version: 1
    runtime: python
    api_version: 1
    
    handlers:
    - url: /upload
      script: synoext.py
    
    - url: /file/\w+
      script: synoext.py
    
    - url: /cleanup
      script: synoext.py
    

    synoext.py

    import datetime
    import logging
    import urlparse
    
    from google.appengine.ext import webapp
    from google.appengine.ext.webapp.util import run_wsgi_app
    from google.appengine.ext import db
    from google.appengine.api import urlfetch
    
    class Files(db.Model):
        file = db.BlobProperty()
        added = db.DateTimeProperty(auto_now_add=True)  
    
    class UploadFile(webapp.RequestHandler):
        def post(self):
            logging.info('(POST) Uploading new file')
            # saving file in the database
            file = Files()
            file.file = db.Blob(self.request.get("file"))
            file.put()
    
            self.response.out.write('http://myapp.appspot.com/' + str(file.key()))
    
    class GetFile(webapp.RequestHandler):
        def get(self, key):
            file = db.get(key)
            if file is not None:
                self.response.headers['Content-Type'] = 'application/x-bittorrent'
                self.response.out.write(file.file)
            else:
                self.response.set_status(404)
    
    class Cleanup(webapp.RequestHandler):
        def get(self):
            '''Automatically run job (cron) to delete old records (maximum 10000)
            from Files database (records, which are older than 5 minutes)
            '''
            fiveMinutesAgoDate = datetime.datetime.now() - datetime.timedelta(minutes=5)
    
            q = db.GqlQuery("SELECT * FROM Files WHERE added < :1", fiveMinutesAgoDate)
            results = q.fetch(10000)
            db.delete(results)
    
            self.response.out.write('{"result": true}')
    
    
    application = webapp.WSGIApplication(
                                         [('/upload', UploadFile),
                                          ('/file/(\w+)', GetFile),
                                          ('/cleanup', Cleanup)],
                                         debug=True)
    
    def main():
        run_wsgi_app(application)
    
    if __name__ == "__main__":
        main()
    

    这是对的吗?方法是否正确?或者,我不应该使用数据存储区吗?

    UPD 即可。奇怪,但是下面的代码

    def get(self, key):
        file = db.get(key)
        if file is not None:
    
    如果使用了错误的密钥,则

    无法正常工作。 这有什么不对?

2 个答案:

答案 0 :(得分:3)

从粗略看一下代码,你的方法应该有效。但是,您可能希望在数据存储区中使用Blobstore而不是blob,具体取决于您的需求以及您尝试投放的文件的大小。

答案 1 :(得分:1)

由于存储的文件很小,所以你一定要按照正确的方式使用datastore

一些建议:

  1. 由于您只需要删除密钥,因此您应该只使用SELECT __key__ FROM Files WHERE ..查询密钥,以节省一些资源。

  2. 如果文件数量很大,您可以使用mapper-api删除所有条目;您可以使用control api

  3. 从代码中启动mapreduce作业
  4. /file/(\w+)未捕获url applications的每个base64编码密钥,_-都是有效字符,您应该将它们与此类匹配/file/([\w_-]+)