2008-09-17 13 views
76

Estoy planeando crear una aplicación web que permita a los usuarios degradar sus archivos visuales de proyectos de estudio. Sin embargo, parece que Google App Engine acepta la carga de archivos y el almacenamiento plano de archivos en el servidor de Google a través de db.TextProperty y db.BlobProperty.Subir archivos en Google App Engine

Estaré contento de que cualquiera pueda proporcionar ejemplos de código (tanto del lado del cliente como del servidor) sobre cómo se puede hacer esto.

+0

@ user858915 El enlace está roto :( – Marco

Respuesta

41

Aquí hay un archivo completo y de trabajo. Saqué el original del sitio de Google y lo modifiqué para hacerlo un poco más real.

Algunas cosas a destacar:

  1. Este código utiliza la BlobStore API
  2. El propósito de esta línea en la clase ServeHandler será la de "fijar" la clave de modo que se deshace de cualquier nombrar mangling que pueda haber ocurrido en el navegador (que no observó ningún en Chrome)

    blob_key = str(urllib.unquote(blob_key)) 
    
  3. La cláusula "save_as" al final de esto es importante. Se asegurará de que el nombre del archivo no se destruya cuando se envía a su navegador. Deshazte de él para observar lo que sucede.

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

buena suerte!

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="/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() 
+0

funcionó para mí - gracias – printminion

+0

Esta debería ser la respuesta aceptada. – Brett

+0

Es sorprendente que esto funcione para todos menos para mí ... 'self .__ uploads' en' blobstore_handler' es 'None' cuando pruebo esto. – Tim

1

No puede almacenar archivos ya que no hay un sistema de archivos tradicional. Sólo se puede almacenar en su propio almacén de datos (en un campo definido como BlobProperty)

Hay un ejemplo en el enlace anterior:

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

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

No hay archivo plano almacenar en Google App Engine. Todo tiene que ir al Datastore que es un poco como una base de datos relacional pero no del todo.

Puede almacenar los archivos como atributos TextProperty o BlobProperty.

Hay un límite de 1 MB en las entradas de DataStore que puede o no ser un problema.

+0

Cómo guardar archivos de más de 1mb. Estoy usando https://github.com/ckopanos/django-google-cloud-storage –

10

hay un hilo de Grupos de Google al respecto:

Uploading Files

Con una gran cantidad de código útil, esa discusión me ayudó mucho en la posibilidad de subir archivos.

49

De hecho, esta pregunta se responde en la documentación de App Egnine. Vea un ejemplo en Uploading User Images.

código HTML, dentro <forma> </forma >: Código

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

Python:

class Guestbook(webapp.RequestHandler): 
    def post(self): 
    greeting = Greeting() 
    if users.get_current_user(): 
     greeting.author = users.get_current_user() 
    greeting.content = self.request.get("content") 
    avatar = self.request.get("img") 
    greeting.avatar = db.Blob(avatar) 
    greeting.put() 
    self.redirect('/')
+0

No me gusta este enfoque causarte información de tipo de mimo suelto – santiagobasulto

+0

@santiagobasulto: ¿Por qué no lo comprueba usted mismo? – vietean

+0

No quiero comprobarlo. Cuando tiene que mostrar una imagen, debe proporcionar información de tipo MIME (si la imagen es JPG, GIF , etc.) por lo tanto, debe proporcionar el encabezado HTTP de tipo de contenido. Si carga la imagen con la solución que proporciona, no sabrá en el futuro el tipo de contenido de la foto, ergo, no puede establecer el encabezado , ergo, los buscadores antiguos tendrán problemas para mostrar la imagen (debido a la ausencia del tipo de contenido) – santiagobasulto

3

Si el sigue teniendo un problema, compruebe que está utilizando enctype en la etiqueta de forma

No:

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

Sí:

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

Estaba obteniendo un error de codificación antes de implementar su respuesta –

+1

Una verdadera molestia para mí cuando estaba haciendo esto no incluía el "tamaño" para el tipo de entrada de archivo. Estuve probando con Safari, que aparentemente tiene una longitud de archivo muy corta por defecto (?) Y todo lo que obtuve en GAE para el contenido del archivo era el nombre del archivo. Solo una palabra de advertencia que podría salvar a alguien con un pequeño dolor de cabeza. –

1

Personalmente me encontré con el tutorial describe here útil cuando se utiliza el tiempo de ejecución de Java con GAE. Por alguna razón, cuando traté de cargar un archivo usando

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

me encontré con que mi clase HttpServlet por alguna razón no aceptaría la forma con el atributo 'enctype'. Sin embargo, eliminarlo funciona, esto significa que no puedo cargar ningún archivo.

+1

Puede ser porque está utilizando el método get, intente configurarlo para publicar en su lugar. No estoy seguro si funcionará, pero vale la pena intentarlo. – slashnick

6

Google ha lanzado un servicio para almacenar archivos de gran tamaño. Eche un vistazo al blobstore API documentation. Si sus archivos son> 1MB, debe usarlo.

+0

Cómo guardar archivos> 1mb. Estoy usando github.com/ckopanos/django-google-cloud-storage –

6

lo intento hoy, funciona de la siguiente manera:

mi versión SDK es 1.3.x

página HTML:

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

código del servidor:

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

No funciona para mí. –

0

I han observado algún comportamiento extraño al cargar archivos en App Engine. Cuando se envía el siguiente formulario:

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

Y luego de extraer el img de la solicitud de la siguiente manera:

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

La variable img_contents es un str() en Google Chrome, pero es Unicode en Firefox. Y como ahora, el constructor db.Blob() toma una cadena y lanzará un error si pasa una cadena Unicode.

¿Alguien sabe cómo esto puede solucionarse?

Además, lo que me parece absolutamente extraño es que cuando copio y pego la aplicación Libro de Visitas (con avatares), funciona perfectamente. Hago todo exactamente de la misma manera en mi código, pero simplemente no funciona. Estoy muy cerca de sacarme el pelo.

+2

: D El formulario decía: mutlipart/form-data en lugar de multipart/form-data. Chrome es lo suficientemente inteligente como para corregir el error tipográfico, Firefox no lo es. –

0

No es una forma de utilizar el sistema de archivos planos (al menos en la perspectiva de uso)

Hay esta Google App Engine Virtual FileSystem project. que se implementa con la ayuda de las API de almacén de datos y Memcache para emular un sistema de archivos común. Usando esta biblioteca puede usar en proyectos de acceso similar a un sistema de archivos (lectura y escritura).