Завантажте файли в Google App Engine


79

Я планую створити веб-програму, яка дозволяє користувачам знизити версію своїх файлів проектів Visual Studio. Однак, схоже, Google App Engine приймає завантаження файлів і зберігання файлів на сервері Google через db.TextPropertyі db.BlobProperty.

Я буду радий, що будь-хто може надати зразок коду (як клієнтський, так і серверний) про те, як це можна зробити.


@ user858915 Посилання розірвано :(
Марко

Відповіді:


44

Ось повний, робочий файл. Я дістав оригінал із сайту Google і змінив його, щоб зробити його трохи реальнішим.

Кілька речей, на які слід звернути увагу:

  1. Цей код використовує API BlobStore
  2. Призначення цього рядка в класі ServeHandler - "виправити" ключ, щоб він позбувся будь-якого перекручування імен, яке могло статися в браузері (я не спостерігав жодного в Chrome)

    blob_key = str(urllib.unquote(blob_key))
    
  3. Важливим є пункт "save_as" в кінці цього. Він переконається, що ім’я файлу не спотворюється, коли воно надсилається у ваш браузер. Позбудьтеся цього, щоб спостерігати, що відбувається.

    self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)
    

Щасти!

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

        for b in blobstore.BlobInfo.all():
            self.response.out.write('<li><a href="https://stackoverflow.com/serve/%s' % str(b.key()) + '">' + str(b.filename) + '</a>')

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload_files = self.get_uploads('file')
        blob_info = upload_files[0]
        self.redirect('/')

class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, blob_key):
        blob_key = str(urllib.unquote(blob_key))
        if not blobstore.get(blob_key):
            self.error(404)
        else:
            self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)

def main():
    application = webapp.WSGIApplication(
          [('/', MainHandler),
           ('/upload', UploadHandler),
           ('/serve/([^/]+)?', ServeHandler),
          ], debug=True)
    run_wsgi_app(application)

if __name__ == '__main__':
  main()

Дивно, що це працює для всіх, крім мене ... self.__uploadsв blobstore_handlerтому, Noneколи я пробую це.
Тім

49

Насправді на це питання відповідає документація App Egnine. Див. Приклад завантаження зображень користувача .

HTML-код, всередині <form> </form>:

<input type = "file" name = "img" />

Код Python:

клас Гостьова книга (webapp.RequestHandler):
  def post (self):
    привітання = Привітання ()
    якщо users.get_current_user ():
      привітання.автор = users.get_current_user ()
    pozdrav.content = self.request.get ("вміст")
    avatar = self.request.get ("img")
    pozdrav.avatar = db.Blob (аватар)
    привітання.put ()
    self.redirect ('/')

Не подобається такий підхід, оскільки ви втрачаєте інформацію про тип mime.
santiagobasulto

@santiagobasulto: Чому б вам не перевірити це ми самі?
vietean

Я не хочу це перевіряти. Коли вам потрібно відобразити зображення, ви повинні надати інформацію про тип mime (незалежно від того, чи є це зображення у форматі JPG, GIF тощо), тому ви повинні вказати заголовок HTTP типу вмісту. Якщо ви завантажите зображення із запропонованим вами рішенням, то в майбутньому ви не знатимете тип вмісту зображення, ergo, ви не можете встановити заголовок, ergo, старі дивні браузери матимуть проблеми з відображенням зображення ( через відсутність типу вмісту)
santiagobasulto

1
Якщо ви не перевіряєте тип mime, ви довіряєте клієнту, залишаючи вас відкритими для атак чорних капелюхів або неправильно налаштованих типів mime в клієнті. Якщо ви збираєтеся це зробити, ви можете просто довіряти самому розширенню файлу.
Nacho Coloma


6

Google випустив сервіс для зберігання великих файлів. Погляньте на документацію щодо API blobstore . Якщо ваші файли мають розмір> 1 Мб, вам слід використовувати їх.


Як зберегти файли> 1 Мб. Я використовую github.com/ckopanos/django-google-cloud-storage
Geo Jacob

6

Я намагаюся сьогодні, це працює наступним чином:

моя версія sdk - 1.3.x

HTML-сторінка:

<form enctype="multipart/form-data" action="/upload" method="post" > 
<input type="file" name="myfile" /> 
<input type="submit" /> 
</form> 

Код сервера:

file_contents = self.request.POST.get('myfile').file.read() 

3

Якщо проблема все ще виникає, перевірте, чи використовуєте ви enctype у тезі форми

Ні:

<form encoding="multipart/form-data" action="/upload">

Так:

<form enctype="multipart/form-data" action="/upload">

Я отримав помилку кодування, перш ніж застосувати вашу відповідь
Джедер Діас,

1
Справжньою надокучливою проблемою для мене, коли я це робив, не було включення "розміру" для типу введення файлу. Я тестував у Safari, який, мабуть, має дуже коротку довжину файлу за замовчуванням (?), І все, що я отримував у GAE щодо вмісту файлу, було ім'я файлу. Лише слово попередження, яке може врятувати когось від незначного головного болю.
Джон Картер,

1

Ви не можете зберігати файли, оскільки не існує традиційної файлової системи. Ви можете зберігати їх лише у власному сховищі даних (у полі, визначеному як BlobProperty )

Є приклад у попередньому посиланні:

class MyModel(db.Model):
  blob = db.BlobProperty()

obj = MyModel()
obj.blob = db.Blob( file_contents )

1

Особисто я знайшов описаний тут підручник корисним при використанні часу роботи Java з GAE. З якоїсь причини, коли я намагався завантажити файл за допомогою

<form action="/testservelet" method="get" enctype="multipart/form-data">
    <div>
        Myfile:<input type="file" name="file" size="50"/>
    </div>

    <div>
        <input type="submit" value="Upload file">
    </div>
</form>

Я виявив, що мій клас HttpServlet з якихось причин не приймає форму з атрибутом 'enctype'. Видалення його працює, однак це означає, що я не можу завантажувати жодні файли.


1
Це може бути тому, що ви використовуєте метод get, спробуйте замість цього встановити його для публікації. Я не впевнений, чи це спрацює, але варто спробувати.
slashnick

0

У Google App Engine немає плоских файлів, які зберігаються. Все має входити до сховища даних, яке трохи нагадує реляційну базу даних, але не зовсім.

Ви можете зберігати файли як атрибути TextProperty або BlobProperty .

Існує обмеження в 1 МБ для записів DataStore, що може бути проблемою чи не.


Як зберегти файли розміром більше 1 Мб. Я використовую github.com/ckopanos/django-google-cloud-storage
Geo Jacob

0

Я спостерігав дивну поведінку під час завантаження файлів в App Engine. Коли ви подаєте таку форму:

<form method="post" action="/upload" enctype="multipart/form-data">
    <input type="file" name="img" />
    ...
</form>

А потім ви витягуєте imgз запиту наступним чином:

img_contents = self.request.get('img')

img_contentsЗмінна є str()в Google Chrome, але це юнікода в Firefox. Як і зараз, db.Blob()конструктор бере рядок і видасть помилку, якщо ви передасте рядок Unicode.

Хтось знає, як це можна виправити?

Крім того, мені здається абсолютно дивним те, що коли я копіюю та вставляю додаток Гостьова книга (з аватарами), він працює чудово. Я роблю все точно так само у своєму коді, але це просто не буде працювати. Я дуже близько вирвати волосся.


2
: D У формі написано: mutlipart / form-data замість multipart / form-data. Chrome досить розумний, щоб виправити друкарську помилку, Firefox - ні.
Хонза Покорний

0

Існує спосіб використання плоскої файлової системи (щонайменше в перспективі використання)

Існує цей проект Google App Engine Virtual FileSystem . що реалізовано за допомогою API зберігання даних та memcache для емуляції звичайної файлової системи. За допомогою цієї бібліотеки ви можете використовувати для проектування подібний доступ до файлової системи (читання та запис) .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.