Как сохранить загруженный файл, а затем вернуть его с помощью GAE? - PullRequest
1 голос
/ 27 июля 2011

Мне нужно создать следующее приложение с использованием GAE:

  1. Пользователь загружает какой-то файл (скажем, POST, что myapp.appspot.com/upload);
  2. Мне нужночтобы сохранить это (в хранилище данных?) и вернуть ссылку;
  3. На основе предоставленной ссылки пользователь сможет загрузить файл в течение следующих 5 минут.

Я создалследующее:

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 ]

3 голосов
/ 27 июля 2011

Из беглого просмотра кода ваш подход должен работать. Однако вы можете использовать Blobstore вместо больших двоичных объектов в хранилище данных, в зависимости от ваших потребностей и размера файлов, которые вы пытаетесь обслуживать.

1 голос
/ 27 июля 2011

Поскольку хранимые файлы довольно малы, вам обязательно следует использовать datastore, как вы правильно сделали.

Некоторые предложения:

  1. Так как вам просто нужно удалить ключи, вам нужно запросить только ключи с SELECT __key__ FROM Files WHERE .. сохранением некоторых ресурсов.

  2. Если количество файлов будет огромным, вы можете использовать mapper-api , чтобы удалить все ваши записи; Вы можете запускать задания mapreduce из своего кода, используя control api .

  3. /file/(\w+) не перехватывает все закодированные в base64 ключи для приложений url , _ и - являются допустимыми символами, и вы должны сопоставить их с чем-то вроде этого /file/([\w_-]+)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...