I am am using Google App Engine in Python and I want users to be able to upload a video, which is functioning properly by following their basic example but then I want to be able to get the user to add additional information about the video, like the title and category and a summary while it is uploading. Is there any way I can make the upload asynchronous so that the user doesn't have to wait the whole time the video is uploading?
I know about the create_upload_url_async() method but that doesn't do what I am trying.
Right now I have the following which uploads and serves but I want to make an intermediate step where the user can add the info preferably on the same screen as the UploadHandler while it is uploading.
class VideoHandler(BlogHandler):
def get(self):
user = self.get_user()
upload_url = blobstore.create_upload_url('/uploadingvideo')
self.render('videohandler.html', user=user, upload_url=upload_url)
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
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))
I'd be glad to provide more information if you need it.
this has been troubling me alot too clifgray. the solution is to build your form around the blob form.
Here's google's example on how to submit data to the blob store.
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
Just remove the self redirect bit at the bottom of the code and add some code to handle your form.
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.video = str(blob_info.key())
greeting.content = self.request.get('content')
greeting.put()
Your form in your django template should look something like this:
form action="{{ upload_url }}" enctype="multipart/form-data" method="post">
textarea name="content" placeholder="write something about this video.." tabindex="1" rows="2" cols="40"></textarea>
input name="file" type="file" >
input name="submit" type="submit" value="Submit" />
/form>
There you have it. hope this helps
Related
I just follow GAE's document (https://developers.google.com/appengine/docs/python/blobstore/#Python_Uploading_a_blob) to write upload handler to upload blobstore, when I select one file on computer and click Submit button on HTML page, it will show 'The url "/upload" does not match any handlers.'
Any comments is appreciated.
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
upload_url = blobstore.create_upload_url('/upload')
logging.info(upload_url)
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>""")
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
logging.info('Upload handler')
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
logging.info(upload_files)
self.redirect('/serve/%s' % blob_info.key())
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
resource = str(urllib.unquote(resource))
logging.info(resource)
blob_info = blobstore.BlobInfo.get(resource)
self.send_blob(blob_info)
application = webapp2.WSGIApplication([
('/', MainPage),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler),
], debug=True)
[Update1]
After I click submit button, I check dev-server Blobstore Viewer, I found the file has been uploaded there, however, my chrome browser still show 'The url "/upload" does not match any handlers.'. This is why?
I want to ask my question by self that maybe someone encounter similar issue as me.
After I change from
- url: /
script: AppWS.application
to
- url: (/.*)*
script: AppWS.application
everything is OK.
I'm using this link as an example to uploading images:
https://gist.github.com/jdstanhope/5079277
My HTML code:
<form action="/upload_image" method="post" id="form1" runat="server">
<div class="fileButtons">
<input type='file' id="imgInp" name="imgInput" accept="image/*"/><br><br>
<input type='button' id='remove' value='Remove' />
</div></form>
main.py:
class SetImage(webapp2.RequestHandler):
def post(self):
logging.debug("test")
id = str(self.request.get('id'))
image = self.request.get('imgInput')
app = webapp2.WSGIApplication([('/upload_image', SetImage),
('/', MainPage)], debug=True)
But when I add an image, nothing is being done, and the log console doesn't print:
logging.debug("test")
The recommended way of uploading images to GAE is by using blobstore.
Here is a quick breakdown of the doc to help you achieve this fast:
Imports:
import os
import urllib
import webapp2
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
Serve the form HTML. this form performs the POST to GAE with the selected files data:
class MainHandler(webapp2.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>""")
Add a handler for receiving the POST data (binary content of the file). the last line in this function is to redirect the response to the location from where the file could be downloaded:
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
# 'file' is file upload field in the form
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
Add handler to serve the image that you uploaded using the UploadHandler described above:
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
resource = str(urllib.unquote(resource))
blob_info = blobstore.BlobInfo.get(resource)
self.send_blob(blob_info)
And finally, define the routes for the app:
app = webapp2.WSGIApplication([('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler)],
debug=True)
Regarding the issue of your log statement not firing: The default log level for dev_appserver.py is info, which you can override with the --dev_appserver_log_level flag.
Reference the new dev_appserver documentation.
To access uploaded files from a multipart/form-data POST request, the webapp2 documentation states that they're available in request.POST.
I have been banging my head against the wall on this one, for some reason I am having trouble tying the different aspects of Google App Engine together to make this work.
Basically I want to let a user upload a photo to the Blobstore, which I have working in the below code, and then I want to put the BlobKey into a list which will be stored in a database entity. So here is my code to upload the image and where in here can I get the BlobKey so that I can store it?
class MainHandler(BlogHandler):
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>""")
#there is a lot more code in here where I get all the following info but it isn't relevant
location_db = Location(
description=description,
submitter=submitter,
user_id=user_id,
title=title,
locationtype = locationtype)
#This is what I would like to do but I don't know where to get thr BlobKey
location_db.blobRefs.append(BlobKey)
location_db.put()
for b in blobstore.BlobInfo.all():
self.response.out.write('<li>' + str(b.filename) + '')
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
self.redirect('/main')
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)
Here:
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
I think it's that
blob_info.key()
you are missing. Grab that, stuff it into your list. Docs also note:
In this handler, you can store the blob key with the rest of your application's data model. The blob key itself remains accessible from the blob info entity in the datastore.
https://developers.google.com/appengine/docs/python/blobstore/overview#Serving_a_Blob
Client side (javascript) uploads the application with XMLHttpRequest:
var req = new XMLHttpRequest();
req.open('POST', my_app_url, false);
req.setRequestHeader("Content-Length", req.length);
req.sendAsBinary(req.binary);
I use datastore on the server side (not blobstore).
How can I save uploaded file to the datastore? I've found that ServletFileUpload can be used with Java. But how to do the same with Python?
You should use self.request.body
class YourUploadHandler(webapp.RequestHandler):
def post(self):
your_binary_content = self.request.body
If you mean on the appengine side, you just have to have a blobproperty. So something like...
class SomeEntity(db.Model):
file_data = db.BlobProperty()
class AddData(webapp.RequestHandler)
def post(self):
data = self.request.get("filedata")
e = SomeEntity(file_data = db.Blob(data))
e.put()
As a note, I'm not sure if the code you posted above to send the request is correct, but you can upload the file with a simple html form, something like this:
<form action="/url_to_adddata_handler/" method="post">
<input type="file" name="filedata">
<input type="submit" value="Submit">
</form>
I'm trying to associate a video file to a record with a bunch of properties, but can't seem to allow the user to do everything in one form - name the video, provide description and answer some question, AND upload the file.
Here are the steps I'd like to perform:
User is served with a page containing a form with the following fields: Name, Description, File selector.
The file gets stored as a blob and the id gets recorded together with name and description.
Does anyone have any examples of doing this I could learn from or a tutorial you could point me to? The one from google only shows uploading the file and getting redirected to it.
Thanks and sorry for a newbish question!
http://demofileuploadgae.appspot.com/ - My demo uploader to the blobstore.
My code for the upload: http://code.google.com/p/gwt-examples/source/browse/trunk/DemoUpload/src/org/gonevertical/upload/#upload/server%3Fstate%3Dclosed
Here's the code I'm using to upload images and associate them with articles. The toughest bit was getting the article id to get to the upload handler, I solved it by setting the file name as the article id to get around the problem.
from lib import urllib2_file
from lib.urllib2_file import UploadFile
# this view serves a task in a queue
def article(request):
article = Article.objects.get(id=form.cleaned_data['article'])
try:
image = StringIO(urllib2.urlopen(image_url).read())
except (urllib2.HTTPError, DownloadError):
article.parsed = True
article.save()
else:
image = UploadFile(image, '.'.join([str(article.id), image_url.rsplit('.', 1)[1][:4]]))
upload_url = blobstore.create_upload_url(reverse('Articles.views.upload'))
try:
urllib2.urlopen(upload_url, {'file': image})
except (DownloadError, RequestTooLargeError):
pass
return HttpResponse(json.dumps({'status': 'OK'}))
def upload(request):
if request.method == 'POST':
blobs = get_uploads(request, field_name='file', populate_post=True)
article = Article.objects.get(id=int(blobs[0].filename.split('.')[0]))
article.media = blobs[0].filename
article.parsed = True
article.save()
return HttpResponseRedirect(reverse('Articles.views.upload'))
else:
return HttpResponse('meow')
def upload(request):
if request.method == 'POST':
blobs = get_uploads(request, field_name='file', populate_post=True)
article = Article.objects.get(id=int(blobs[0].filename.split('.')[0]))
article.media = blobs[0].filename
article.parsed = True
article.save()
return HttpResponseRedirect(reverse('Articles.views.upload'))
else:
return HttpResponse('meow')
# this serves the image
def image(request):
blob = BlobInfo.gql("WHERE filename='%s' LIMIT 1" % request.form.cleaned_data['id'])[0]
return HttpResponse(BlobReader(blob.key()).read(),
content_type=blob.content_type)
Also you'll need this http://fabien.seisen.org/python/urllib2_file/
Here is how I did it. It is more straight forward than you think. Note the following taken from Blobstore overview.
"When the Blobstore rewrites the user's request, the MIME parts of the uploaded files have their bodies emptied, and the blob key is added as a MIME part header. All other form fields and parts are preserved and passed to the upload handler." In the upload handler is where you can do whatever it is you want with the other form fields.
class Topic(db.Model):
title = db.StringProperty(multiline=False)
blob = blobstore.BlobReferenceProperty()
imageurl = db.LinkProperty()
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>
<div><label>Title:</label></div>
<div><textarea name="title" rows="1" cols="25"></textarea></div><input type="submit"
name="submit" value="Submit"> </form>""")
self.response.out.write('<br><br><h2>TOPIC LIST</h2><table border="1"><tr><td>')
for topic in Topic.all():
self.response.out.write('<div><img src="%s=s48"/>' % topic.imageurl)
self.response.out.write('<div><b>Image URL: </b><i>%s</i></div>' % topic.imageurl)
self.response.out.write('<div><b>Title: </b><i>%s</i></div>' % topic.title)
self.response.out.write('</td></tr></table><br>')
self.response.out.write('</body></html>')
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
topic = Topic()
topic.title = self.request.get("title")
topic.blob = blob_info.key()
topic.imageurl = images.get_serving_url(str(blob_info.key()))
topic.put()
self.redirect('/')
def main():
application = webapp.WSGIApplication(
[('/', MainHandler),
('/upload', UploadHandler),
], debug=True)
run_wsgi_app(application)