Upload da arquivo no Google App Engine (BlobProperty)
Newsletter about software engineering, team management, team building, books and lots of notes I take after reading/studying (mine or yours)… :D
Essa semana que passou tive uma necessidade para um sistema de trabalhar com UPLOAD de arquivos, ate ai é simples, só que o sistema estava em Google App Engine, depois de apanhar um pouco resolvi fazer um post aqui no Blog para deixar documentado como não é complicado trabalhar com BlobProperty no BigTable.
Primeiro vamos criar um Modal onde vai ter dois campo o arquivo e o mimetype dele:
class DatastoreFile(db.Model):
data = db.BlobProperty(required=True)
mimetype = db.StringProperty(required=True)
Agora vamos criar a views onde ele vai processar o formulario e o POST do formulario:
class MainHandler(webapp.RequestHandler):
def get(self):
self.response.out.write(template.render("upload.html", {}))
def post(self):
file = self.request.POST['file']
entity = DatastoreFile(data=file.value, mimetype=file.type)
entity.put()
file_url = "http://%s/%d/%s" % (self.request.host, entity.key().id(), file.name)
self.response.out.write("Your uploaded file is now available at %s" % (file_url,))
Podemos notar que na definição get() temos apenas a renderização do "upload.html", o conteudo dele é bem simples, temos um input do tipo file e outro submit:
<html>
<head>
<title>File Upload</title>
</head>
<body>
<form method="post" action="/" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="Upload" />
</form>
</body>
</html>
Falando da definição post() que esta na classe MainHandler ela que faz o trabalho de fazer o UPLOAD do arquivo para dentro do BlobProperty, é um processo bem simples, a variável "file" recebe o POST do input file, depois disso chamamos o modal que tem o nome de DatastoreFile passando dois parâmetros que é os dois campos criados, o data e mimetype, depois disso é só fazer o put() que seja salvo no banco de dados. Dentro do post() eu gero o link para download do arquivo na variável file_url, onde passo o HOST (url do sistema), id() (do arquivo que foi feito upload) e file name (Nome do campo que recebeu o arquivo).
Agora temos que fazer a classe para download do arquivo onde vamos mudar o Content-Type do response para o mime-type do arquivo que foi feito o upload, exemplo: fiz o upload de um arquivo no formato JPG o mime type dele é "image/jpeg", então tenho que fazer o responser renderizar em formatado "image/jpeg".
Na URL que montamos para download passamos a seguinte informação id e file name onde temos que criar uma definição get() que receba essas informações:
class DownloadHandler(webapp.RequestHandler):
def get(self, id, filename):
entity = DatastoreFile.get_by_id(int(id))
self.response.headers['Content-Type'] = entity.mimetype
self.response.out.write(entity.data)
Recebendo as duas variáveis podemos fazer um consulta no BigTable de forma simples onde busco o id, pego o retorno do banco de dados e coloco que o response.headers['Content-Type'] é o mime-type que esta salvo no banco e depois é só escrever o arquivo na tela.
Agora vamos criar as rotas da URL:
def main():
application = webapp.WSGIApplication([
('/', MainHandler),
('/(\d+)/(.*)', DownloadHandler)
],debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
Quem ainda estiver com duvida pode dar uma olhar no repositorio:
https://bitbucket.org/avelino/post_py_upload_de_arquivo_no_gae/src