Je prévois de créer une application Web qui permet aux utilisateurs de rétrograder leurs fichiers de projet Visual Studio. Cependant, il semble que Google App Engine accepte le téléchargement de fichiers et le stockage de fichiers plats sur le serveur Google via db.TextProperty
et db.BlobProperty
.
Je serai heureux que quiconque puisse fournir un exemple de code (côté client et côté serveur) sur la façon dont cela peut être fait.
Voici un dossier de travail complet. J'ai retiré l'original du site Google et l'ai modifié pour le rendre un peu plus réel.
Quelques points à noter:
Le but de cette ligne dans la classe ServeHandler est de "corriger" la clé afin qu'elle se débarrasse de toute altération de nom qui aurait pu se produire dans le navigateur (je n'en ai pas observé dans Chrome)
blob_key = str(urllib.unquote(blob_key))
La clause "save_as" à la fin de ceci est importante. Il s'assurera que le nom du fichier ne soit pas modifié lorsqu'il est envoyé à votre navigateur. Débarrassez-vous-en pour observer ce qui se passe.
self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)
Bonne chance!
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 __== '__main__':
main()
En fait, cette question trouve sa réponse dans la documentation App Egnine. Voir un exemple sur Téléchargement d'images utilisateur .
Code HTML, à l'intérieur de <form> </form>:
<input type = "file" name = "img" />
Code Python:
livre d'or de classe (webapp.RequestHandler): def post (self): greeting = Greeting () if users.get_current_user (): salutation.author = users.get_current_user () salutation.content = self.request.get ("contenu") avatar = self.request.get ("img") salutation.avatar = db.Blob (avatar) salutation.put () self.redirect ('/')
Il y a un fil dans Google Groupes à ce sujet:
Avec beaucoup de code utile, cette discussion m'a beaucoup aidé dans le téléchargement de fichiers.
Je l'essaie aujourd'hui, cela fonctionne comme suit:
ma version sdk est 1.3.x
page html:
<form enctype="multipart/form-data" action="/upload" method="post" >
<input type="file" name="myfile" />
<input type="submit" />
</form>
Code serveur:
file_contents = self.request.POST.get('myfile').file.read()
Google a publié un service de stockage de fichiers volumineux. Jetez un œil à documentation de l'API blobstore . Si vos fichiers sont> 1 Mo, vous devez l'utiliser.
Si vous rencontrez toujours un problème, vérifiez que vous utilisez enctype dans la balise de formulaire
Non:
<form encoding="multipart/form-data" action="/upload">
Oui:
<form enctype="multipart/form-data" action="/upload">
Vous ne pouvez pas stocker de fichiers car il n’existe pas de système de fichiers traditionnel. Vous ne pouvez les stocker que dans leur propre DataStore (dans un champ défini comme BlobProperty )
Il y a un exemple dans le lien précédent:
class MyModel(db.Model):
blob = db.BlobProperty()
obj = MyModel()
obj.blob = db.Blob( file_contents )
Personnellement, j'ai trouvé le tutoriel décrit ici utile lors de l'utilisation de Java run time avec GAE. Pour une raison quelconque, lorsque j'ai essayé de télécharger un fichier en utilisant
<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>
J'ai trouvé que ma classe HttpServlet pour une raison quelconque n'acceptait pas le formulaire avec l'attribut 'enctype'. Le supprimer fonctionne, cependant, cela signifie que je ne peux pas télécharger de fichiers.
Il existe un moyen d'utiliser un système de fichiers plat (au moins dans une perspective d'utilisation)
Il y a ceci projet de système de fichiers virtuel Google App Engine . qui est implémenté à l'aide d'API de banque de données et de memcache pour émuler un système de fichiers ordinaire. En utilisant cette bibliothèque, vous pouvez utiliser pour projeter un accès au système de fichiers similaire (lecture et écriture) .
Aucun fichier plat n'est stocké dans Google App Engine. Tout doit aller dans le Datastore qui est un peu comme une base de données relationnelle mais pas tout à fait.
Vous pouvez stocker les fichiers en tant qu'attributs TextProperty ou BlobProperty .
Il existe une limite de 1 Mo sur les entrées DataStore qui peut ou non être un problème.
J'ai observé un comportement étrange lors du téléchargement de fichiers sur App Engine. Lorsque vous soumettez le formulaire suivant:
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="img" />
...
</form>
Et puis vous extrayez le img
de la requête comme ceci:
img_contents = self.request.get('img')
La variable img_contents
Est une str()
dans Google Chrome, mais c'est unicode dans Firefox. Et comme vous le faites maintenant, le constructeur db.Blob()
prend une chaîne et générera une erreur si vous passez une chaîne unicode.
Quelqu'un sait-il comment résoudre ce problème?
De plus, ce que je trouve absolument étrange, c'est que lorsque je copie et colle l'application du livre d'or (avec des avatars), cela fonctionne parfaitement. Je fais tout exactement de la même manière dans mon code, mais cela ne fonctionnera tout simplement pas. Je suis sur le point d'arracher mes cheveux.