Visão geral da API Blobstore Python

Observação: em vez do Blobstore, use o Google Cloud Storage para armazenar dados do blob.

A API Blobstore permite que seu aplicativo disponibilize objetos de dados, chamados blobs, que são muito maiores do que o tamanho permitido para objetos no serviço do Datastore. Os blobs são úteis para exibir arquivos grandes, como arquivos de vídeo ou de imagem, e para permitir que os usuários façam upload de arquivos de dados grandes. Os blobs são criados com o upload de um arquivo por meio de uma solicitação HTTP. Normalmente, seus aplicativos fazem isso apresentando um formulário com um campo de upload de arquivo para o usuário. Quando o formulário é enviado, o Blobstore cria um blob a partir do conteúdo do arquivo e retorna uma referência opaca ao blob, chamada de chave blob, que você pode usar mais tarde para disponibilizar o blob. O aplicativo pode disponibilizar o valor de blob completo em resposta a uma solicitação do usuário ou pode ler o valor diretamente usando uma interface semelhante a um arquivo de streaming.

Apresentação do Blobstore

O Google App Engine inclui o serviço Blobstore. Com ele, os aplicativos podem disponibilizar objetos de dados, limitados somente pela quantidade de dados que podem ser salvos por upload ou download em uma única conexão HTTP. Esses objetos são chamados de valores do Blobstore ou blobs. Os valores do Blobstore são disponibilizados como respostas de gerenciadores de solicitações e criados como uploads por meio de formulários da Web. Os aplicativos não criam dados de blob diretamente. Na verdade, isso é feito indiretamente no envio de um formulário da Web ou em outra solicitação POST HTTP. É possível disponibilizar os valores do Blobstore para o usuário ou acessá-los pelo aplicativo em um stream semelhante a um arquivo, usando a API Blobstore.

Para solicitar que um usuário faça upload de um valor do Blobstore, o aplicativo exibe um formulário da Web com um campo de upload de arquivos. O aplicativo gera o URL de ação do formulário ao chamar a API Blobstore. O navegador do usuário faz upload do arquivo diretamente para o Blobstore por meio do URL gerado. O Blobstore, em seguida, armazena o blob, reescreve a solicitação para conter a chave blob e a transmite para um caminho no aplicativo. Um gerenciador de solicitações nesse caminho do aplicativo pode realizar um processamento extra do formulário.

Para disponibilizar um blob, o aplicativo define um cabeçalho na resposta de saída, e o App Engine substitui a resposta pelo valor do blob.

Os blobs não podem ser modificados depois que são criados, mas é possível excluí-los. Cada blob tem um registro de informações correspondente, no armazenamento de dados, que fornece detalhes sobre o blob, como a hora de criação e o tipo de conteúdo. Você pode usar a chave blob para buscar registros de informações de blobs e para consultar as propriedades deles.

Um aplicativo pode ler um valor do Blobstore por vez usando uma chamada de API. O tamanho máximo de cada parte pode ser até o tamanho máximo de um valor de retorno da API. Esse tamanho é um pouco menor que 32 megabytes, representados em Python pela constante google.appengine.ext.blobstore.MAX_BLOB_FETCH_SIZE. Um aplicativo não pode criar nem modificar valores do Blobstore, exceto por meio de arquivos enviados pelo usuário.

Como usar o Blobstore

Os aplicativos podem usar o Blobstore para aceitar arquivos grandes como uploads de usuários e disponibilizar esses arquivos. Os arquivos são chamados de blobs após o upload. Os aplicativos não acessam blobs diretamente. Em vez disso, os aplicativos funcionam com blobs por meio de entidades de informações de blob (representadas pela classe BlobInfo) no armazenamento de dados.

O usuário cria um blob enviando um formulário HTML que inclui um ou mais campos de entrada de arquivo. O aplicativo chama create_upload_url() para receber o destino (ação) desse formulário, passando à função um caminho de URL de um gerenciador no aplicativo. Quando o usuário envia o formulário, o navegador do usuário encaminha os arquivos especificados diretamente para o Blobstore. O Blobstore reescreve a solicitação do usuário e armazena os dados do arquivo enviado, substituindo os dados desse arquivo por uma ou mais chaves blob correspondentes, e passa a solicitação reescrita para o gerenciador no caminho do URL fornecido para o create_upload_url(). Esse gerenciador pode realizar um processamento adicional com base na chave blob.

O aplicativo pode ler partes de um valor do Blobstore usando uma interface de streaming semelhante a um arquivo. Consulte Classe BlobReader.

Como fazer upload de um blob

Para criar e fazer upload de um blob, siga este procedimento:

1. Criar um URL de upload

Chame blobstore.create_upload_url() para criar o URL de upload do formulário a ser preenchido pelo usuário, passando o caminho do aplicativo para o carregamento quando o POST do formulário for concluído.

upload_url = blobstore.create_upload_url('/upload_photo')

Há uma versão assíncrona, create_upload_url_async(). Ela permite que o código do aplicativo continue em execução enquanto o Blobstore gera o URL de upload.

2. Criar um formulário de upload

O formulário precisa incluir um campo de upload de arquivo, e o enctype do formulário precisa ser definido como multipart/form-data. Quando o usuário envia o formulário, o POST é gerenciado pela API Blobstore, que cria o blob. A API também cria um registro de informações para o blob, armazena o registro no armazenamento de dados e passa a solicitação reescrita para seu aplicativo no caminho fornecido como uma chave blob.

        # To upload files to the blobstore, the request method must be "POST"
        # and enctype must be set to "multipart/form-data".
        self.response.out.write("""
<html><body>
<form action="{0}" method="POST" enctype="multipart/form-data">
  Upload File: <input type="file" name="file"><br>
  <input type="submit" name="submit" value="Submit">
</form>
</body></html>""".format(upload_url))

3. Implementar o gerenciador de uploads

Nesse gerenciador, você pode armazenar a chave blob com o restante do modelo de dados do seu aplicativo. A chave blob em si permanece acessível a partir da entidade de informações do blob no armazenamento de dados. Observe que o blob já estará salvo e as informações do blob estarão no armazenamento de dados depois que o usuário tiver enviado o formulário e o gerenciador for chamado. Se o aplicativo não quiser manter o blob, você precisará excluir o blob imediatamente para evitar que ele se torne órfão:

class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload = self.get_uploads()[0]
        user_photo = UserPhoto(
            user=users.get_current_user().user_id(),
            blob_key=upload.key())
        user_photo.put()

        self.redirect('/view_photo/%s' % upload.key())

O framework do webapp fornece a classe do gerenciador de upload blobstore_handlers.BlobstoreUploadHandler para você analisar os dados do formulário. Para mais informações, consulte a referência de BlobstoreUploadHandler.

Quando o Blobstore reescreve a solicitação do usuário, o corpo das partes MIME dos arquivos enviados é esvaziado e a chave blob é adicionada como cabeçalho de parte MIME. Todos os outros campos e partes do formulário são preservados e passados para o gerenciador de upload. Se não for especificado um tipo de conteúdo, o Blobstore tentará deduzi-lo a partir da extensão do arquivo. Se nenhum tipo de conteúdo puder ser determinado, o tipo application/octet-stream será atribuído ao blob recém-criado.

Como disponibilizar um blob

Para disponibilizar blobs, você precisa incluir um gerenciador de download de blob como um caminho do aplicativo. O aplicativo disponibiliza um blob definindo um cabeçalho na resposta de saída. A amostra a seguir usa a estrutura do webapp. Ao usar webapp, o gerenciador precisa passar a chave do blob desejado para self.send_blob(). Neste exemplo, a chave de blob é passada para o gerenciador de download como parte do URL. Na prática, o gerenciador de download pode receber a chave de blob por qualquer meio escolhido, por exemplo, por meio de outro método ou ação do usuário.

class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            self.error(404)
        else:
            self.send_blob(photo_key)

O framework do webapp fornece a classe do gerenciador de download blobstore_handlers.BlobstoreDownloadHandler para você analisar os dados do formulário. Para mais informações, consulte a referência de BlobstoreDownloadHandler.

Os blobs podem ser disponibilizados a partir de qualquer URL do aplicativo. Para disponibilizar um blob no aplicativo, coloque um cabeçalho especial na resposta que contém a chave blob. O corpo da resposta é substituído pelo conteúdo do blob no App Engine.

Intervalos de bytes do blob

O Blobstore tem compatibilidade com a disponibilização de uma parte de um valor grande, em vez do valor total em resposta a uma solicitação. Para disponibilizar um valor parcial, inclua o cabeçalho X-AppEngine-BlobRange na resposta de saída. O valor dele é um intervalo de bytes HTTP padrão. A numeração de bytes é baseada em zeros. Um X-AppEngine-BlobRange em branco instrui a API a ignorar o cabeçalho do intervalo e disponibilizar o blob completo. Veja alguns exemplos de intervalos:

  • 0-499 disponibiliza os primeiros 500 bytes do valor (bytes de 0 a 499, inclusive).
  • 500-999 disponibiliza 500 bytes a partir do 501º byte.
  • 500- disponibiliza todos os bytes do 501º byte ao final do valor.
  • -500 disponibiliza os últimos 500 bytes do valor.

Se o intervalo de bytes for válido para o valor do Blobstore, o Blobstore enviará um código de status 206 Partial Content e o intervalo de bytes solicitado para o cliente. Se o intervalo não for válido para o valor, o Blobstore enviará 416 Requested Range Not Satisfiable.

O Blobstore não é aceito para vários intervalos de bytes em uma única solicitação (por exemplo, 100-199,200-299), estando eles sobrepostos ou não.

A classe webapp.blobstore_handlers.BlobstoreDownloadHandler inclui recursos para configurar esse cabeçalho usando os índices de byte fornecidos e para derivar o intervalo de bytes automaticamente de um cabeçalho range fornecido pelo usuário.

Aplicativo de amostra completo

No aplicativo de amostra a seguir, o URL principal do aplicativo carrega o formulário em que o usuário faz upload do arquivo e o gerenciador de upload imediatamente chama o gerenciador de download para disponibilizar os dados. O objetivo aqui é simplificar o aplicativo de amostra. Na prática, você provavelmente não usaria o URL principal para solicitar os dados para upload, nem veicularia imediatamente um blob que tivesse acabado de enviar.

from google.appengine.api import users
from google.appengine.ext import blobstore
from google.appengine.ext import ndb
from google.appengine.ext.webapp import blobstore_handlers
import webapp2

# This datastore model keeps track of which users uploaded which photos.
class UserPhoto(ndb.Model):
    user = ndb.StringProperty()
    blob_key = ndb.BlobKeyProperty()

class PhotoUploadFormHandler(webapp2.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload_photo')
        # To upload files to the blobstore, the request method must be "POST"
        # and enctype must be set to "multipart/form-data".
        self.response.out.write("""
<html><body>
<form action="{0}" method="POST" enctype="multipart/form-data">
  Upload File: <input type="file" name="file"><br>
  <input type="submit" name="submit" value="Submit">
</form>
</body></html>""".format(upload_url))

class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload = self.get_uploads()[0]
        user_photo = UserPhoto(
            user=users.get_current_user().user_id(),
            blob_key=upload.key())
        user_photo.put()

        self.redirect('/view_photo/%s' % upload.key())

class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            self.error(404)
        else:
            self.send_blob(photo_key)

app = webapp2.WSGIApplication([
    ('/', PhotoUploadFormHandler),
    ('/upload_photo', PhotoUploadHandler),
    ('/view_photo/([^/]+)?', ViewPhotoHandler),
], debug=True)

Como usar o serviço Imagens com o Blobstore

O serviço Imagens pode usar um valor do Blobstore como fonte de uma transformação. A imagem fonte pode ter tamanho igual ao tamanho máximo de um valor do Blobstore. O serviço Imagens ainda retorna a imagem transformada para o aplicativo. Dessa forma, a imagem transformada precisa ter menos de 32 MB. Isso é útil para criar miniaturas de fotos grandes enviadas por usuários.

Para informações sobre como usar o serviço Imagens com os valores do Blobstore, consulte a documentação do serviço Imagens.

Como usar a API Blobstore com o Google Cloud Storage

Você pode usar a API Blobstore para armazenar blobs no Cloud Storage em vez de armazená-los no Blobstore. É necessário configurar um intervalo conforme descrito na documentação do Google Cloud Storage e especificar o intervalo e o nome de arquivo no parâmetro blobstore.blobstore.create_upload_url gs_bucket_name. No gerenciador de upload, é preciso processar os metadados retornados por FileInfo e armazenar explicitamente o nome do arquivo do Google Cloud Storage necessário para recuperar o blob posteriormente.

Você também pode veicular objetos do Cloud Storage usando a API Blobstore. Os seguintes snippets de código mostram como fazer isso:

"""A sample app that operates on GCS files with blobstore API."""

import cloudstorage
from google.appengine.api import app_identity
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
import webapp2

# This handler creates a file in Cloud Storage using the cloudstorage
# client library and then reads the data back using the Blobstore API.
class CreateAndReadFileHandler(webapp2.RequestHandler):
    def get(self):
        # Get the default Cloud Storage Bucket name and create a file name for
        # the object in Cloud Storage.
        bucket = app_identity.get_default_gcs_bucket_name()

        # Cloud Storage file names are in the format /bucket/object.
        filename = '/{}/blobstore_demo'.format(bucket)

        # Create a file in Google Cloud Storage and write something to it.
        with cloudstorage.open(filename, 'w') as filehandle:
            filehandle.write('abcde\n')

        # In order to read the contents of the file using the Blobstore API,
        # you must create a blob_key from the Cloud Storage file name.
        # Blobstore expects the filename to be in the format of:
        # /gs/bucket/object
        blobstore_filename = '/gs{}'.format(filename)
        blob_key = blobstore.create_gs_key(blobstore_filename)

        # Read the file's contents using the Blobstore API.
        # The last two parameters specify the start and end index of bytes we
        # want to read.
        data = blobstore.fetch_data(blob_key, 0, 6)

        # Write the contents to the response.
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.write(data)

        # Delete the file from Google Cloud Storage using the blob_key.
        blobstore.delete(blob_key)

# This handler creates a file in Cloud Storage using the cloudstorage
# client library and then serves the file back using the Blobstore API.
class CreateAndServeFileHandler(blobstore_handlers.BlobstoreDownloadHandler):

    def get(self):
        # Get the default Cloud Storage Bucket name and create a file name for
        # the object in Cloud Storage.
        bucket = app_identity.get_default_gcs_bucket_name()

        # Cloud Storage file names are in the format /bucket/object.
        filename = '/{}/blobstore_serving_demo'.format(bucket)

        # Create a file in Google Cloud Storage and write something to it.
        with cloudstorage.open(filename, 'w') as filehandle:
            filehandle.write('abcde\n')

        # In order to read the contents of the file using the Blobstore API,
        # you must create a blob_key from the Cloud Storage file name.
        # Blobstore expects the filename to be in the format of:
        # /gs/bucket/object
        blobstore_filename = '/gs{}'.format(filename)
        blob_key = blobstore.create_gs_key(blobstore_filename)

        # BlobstoreDownloadHandler serves the file from Google Cloud Storage to
        # your computer using blob_key.
        self.send_blob(blob_key)

app = webapp2.WSGIApplication([
    ('/', CreateAndReadFileHandler),
    ('/blobstore/read', CreateAndReadFileHandler),
    ('/blobstore/serve', CreateAndServeFileHandler)], debug=True)

Como usar BlobReader

Um aplicativo pode ler dados de valores do Blobstore usando uma interface semelhante a um objeto file do Python. Essa interface pode começar a ler um valor em qualquer posição de byte e usar várias chamadas de serviço e armazenamento em buffer. Dessa forma, um aplicativo pode acessar o tamanho total do valor, desconsiderando o limite do tamanho de uma resposta de chamada de serviço única.

A classe BlobReader pode usar um desses três valores como um argumento para o construtor:

O objeto implementa os métodos de arquivo familiares para ler o valor. O aplicativo não pode modificar o valor do Blobstore. Os métodos de arquivo para gravação não são implementados.

# Instantiate a BlobReader for a given Blobstore blob_key.
blob_reader = blobstore.BlobReader(blob_key)

# Instantiate a BlobReader for a given Blobstore blob_key, setting the
# buffer size to 1 MB.
blob_reader = blobstore.BlobReader(blob_key, buffer_size=1048576)

# Instantiate a BlobReader for a given Blobstore blob_key, setting the
# initial read position.
blob_reader = blobstore.BlobReader(blob_key, position=0)

# Read the entire value into memory. This may take a while depending
# on the size of the value and the size of the read buffer, and is not
# recommended for large values.
blob_reader_data = blob_reader.read()

# Write the contents to the response.
self.response.headers['Content-Type'] = 'text/plain'
self.response.write(blob_reader_data)

# Set the read position back to 0, then read and write 3 bytes.
blob_reader.seek(0)
blob_reader_data = blob_reader.read(3)
self.response.write(blob_reader_data)
self.response.write('\n')

# Set the read position back to 0, then read and write one line (up to
# and including a '\n' character) at a time.
blob_reader.seek(0)
for line in blob_reader:
    self.response.write(line)

Como fazer solicitações assíncronas

Um aplicativo pode chamar algumas funções do Blobstore que funcionam em segundo plano. O Blobstore realiza a solicitação enquanto o aplicativo faz outras coisas. Para fazer a solicitação, o aplicativo chama uma função assíncrona. A função retorna imediatamente um objeto RPC. Esse objeto representa a solicitação. Quando o aplicativo precisa do resultado da solicitação, ele chama o método get_result() do objeto RPC.

Se o serviço não tiver concluído a solicitação quando o aplicativo chamar get_result(), o método aguardará a conclusão da solicitação (ou o alcance do prazo final ou a ocorrência de um erro). O método retornará o objeto de resultado ou gerará uma exceção se um erro tiver ocorrido durante a realização da solicitação. Por exemplo, este snippet de código

upload_url = blobstore.create_upload_url('/upload')
slow_operation()
self.response.out.write("""<form action="%s" method="POST"
                           enctype="multipart/form-data">""" % upload_url)

torna-se

upload_url_rpc = blobstore.create_upload_url_async('/upload')
slow_operation()
upload_url = upload_url_rpc.get_result()
self.response.out.write("""<form action="%s" method="POST"
                           enctype="multipart/form-data">""" % upload_url)

Neste exemplo, o aplicativo executa o código slow_operation() ao mesmo tempo em que o Blobstore gera o URL de upload.

Cotas e limites

O espaço usado para os valores do Blobstore contribui para a cota de Dados armazenados (faturáveis). As entidades de informações do blob no armazenamento de dados são contabilizadas dentro dos limites relacionados ao armazenamento de dados. O Google Cloud Storage é um serviço pago de acordo com o uso. Por isso, a cobrança será feita conforme a planilha de preços do Cloud Storage.

Para mais informações sobre as cotas de segurança do sistema, consulte Cotas.

Além das cotas de segurança do sistema, os seguintes limites são aplicados especificamente ao uso do Blobstore:

  • O tamanho máximo dos dados do Blobstore que podem ser lidos pelo aplicativo com uma chamada de API é de 32 MB.
  • O número máximo de arquivos que pode ser enviado em um único POST de formulário é 500.
Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Ambiente padrão do App Engine para Python 2