serve images using Google App Engine? - google-app-engine

I am writing a simple application, that lets user upload images, and the application will show the image directly below the upload form. However I can't figure out how to show the image properly. I have tried several answers in stack overflow. None of them seem to answer the questions that I have. Could anyone please look at my code and see what I am doing wrong? Any help would be greatly appreciated.
import os
import urllib
import webapp2
from google.appengine.ext import db
import google.appengine.api.images
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
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>""")
#self.response.headers['Content-Type'] = 'image/png'
images = db.GqlQuery("select * from Images")
serving_url = ""
if images:
for x in images:
serving_url = google.appengine.api.images.get_serving_url(x.key(), 0, False, False)
self.response.out.write("""<div>Image:<img src="%s" </div> """ %serving_url)
else:
self.response.out.write("""<div>No Image Found</div>""")
self.response.out.write("""END</body></html>""")
class Images(db.Model):
image_db = db.BlobProperty()
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, resource):
resource = str(urllib.unquote(resource))
blob_info = blobstore.BlobInfo.get(resource)
self.send_blob(blob_info)
app = webapp2.WSGIApplication([('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler)],
debug=True)

You're doing a few things wrong here.
Firstly, you are correctly using blobstore to store the images. To store reference a blobstore image in a model, you should be using db.BlobReferenceProperty.
Secondly, you're not actually storing that reference in your UploadHandler:
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]
instance = Images(image_db=blob_info)
instance.put()
self.redirect('/')
Finally, your GQL returns the Images instance, not of the blob. So your call to get_serving_url should be:
serving_url = images.get_serving_url(x.image_db)

Related

Read File from GAE blobstore

Using the code below,
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>""")
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, resource):
resource = str(urllib.unquote(resource))
blob_info = blobstore.BlobInfo.get(resource)
self.send_blob(blob_info)
app = webapp.WSGIApplication(
[('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler),
], debug=True)
if __name__ == '__main__':
run_wsgi_app(app)
I was able to read files like .pdf,.txt, and media files from my blob store. But files like .doc,.docx returns files that are not readable.
I have tried using blob_reader but still did not work, how do I get to read files like .doc and .docx?
Your browser cannot handle doc files. But you can download the file and open the file with a viewer.
To download a blob, use:
self.send_blob(blob_info,save_as=True)
or:
self.send_blob(blob_info,save_as='amsdoc.docx')

I can not download a blob from GAE BlobStore

What is wrong with this code? I can not download a blob following the download url sent as response of the UploadHandler. I am getting a 404 response from the server.
I have doubts about how to send an url safe version of the blob key.
import urllib
import webapp2
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
MAIN = """<html>
<body>
<form action="%s" method="POST" enctype="multipart/form-data">
<p>Upload File:<input type="file" name="file"></p>
<p><input type="submit" name="submit" value="Submit">
</form>
</body>
</html>
"""
DOWNLOAD = """<html><body><p>%s</p></body></html>"""
class MainHandler(webapp2.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload')
self.response.out.write(MAIN % upload_url)
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is name field in the form
blob_info = upload_files[0]
_key = blob_info.key()
_url = '/download/%s' % str(_key)
_url_text = blob_info.filename
self.response.out.write(DOWNLOAD % (_url, _url_text))
class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
blob_info = blobstore.Blob.get(resource)
self.sendblob(blob_info)
app = webapp2.WSGIApplication([('/', MainHandler),
('/upload', UploadHandler),
('/download/<resource>', DownloadHandler)],
debug=True)
app.yaml file is
application: georef
version: 1
runtime: python27
api_version: 1
threadsafe: false
libraries:
- name: webapp2
version: latest
handlers:
- url: /.*
script: georef.app
It looks like you copy and pasted the code wrong from the docs:
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
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)
You're missing the line to unencode the resource string in case it has any strange characters in it.

GAE upload image then dynamically serve the image

I'm trying to make a simple app on GAE that allows a user to enter a url to an image and a name. The app then uploads this image to the Datastore along with its name.
After the upload the page self redirects and then should send the image back to the client and display it on their machine.
After running all I get is a Server error. Since I am new to GAE please could someone tell me if my code is at least correct.
I can't see what is wrong with my code. (I have checked for correct indentation and whitespace). Below is the code:
The python:
import jinja2 # html template libary
import os
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
import urllib
import urllib2
import webapp2
from google.appengine.ext import db
from google.appengine.api import urlfetch
class Default_tiles(db.Model):
name = db.StringProperty()
image = db.BlobProperty(default=None)
class MainPage(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render())
class Upload(webapp2.RequestHandler):
def post(self):
# get information from form post upload
image_url = self.request.get('image_url')
image_name = self.request.get('image_name')
# create database entry for uploaded image
default_tile = Default_tiles()
default_tile.name = image_name
default_tile.image = db.Blob(urlfetch.Fetch(image_url).content)
default_tile.put()
self.redirect('/?' + urllib.urlencode({'image_name': image_name}))
class Get_default_tile(webapp.RequestHandler):
def get(self):
name = self.request.get('image_name')
default_tile = get_default_tile(name)
self.response.headers['Content-Type'] = "image/png"
self.response.out.write(default_tile.image)
def get_default_tile(name):
result = db.GqlQuery("SELECT * FROM Default_tiles WHERE name = :1 LIMIT 1", name).fetch(1)
if (len(result) > 0):
return result[0]
else:
return None
app = webapp2.WSGIApplication([('/', MainPage),
('/upload', Upload),
('/default_tile_img', Get_default_tile)],
debug=True)
The HTML:
<html>
<head>
<link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />
</head>
<body>
<form action="/upload" method="post">
<div>
<p>Name: </p>
<input name="image_name">
</div>
<div>
<p>URL: </p>
<input name="image_url">
</div>
<div><input type="submit" value="Upload Image"></div>
</form>
<img src="default_tile_img?{{ image_name }}">
</body>
</html>
Any help at all will be so much appreciated. Thanks you!
UPDATE
Thanks to Greg, I know know how to view error logs. As Greg said I was missing a comma, I have updated the code above.
The app now runs, but when I upload an image, no image shows on return. I get the following message in the log:
File "/Users/jamiefearon/Desktop/Development/My Programs/GAE Fully functional website with css, javascript and images/mywebsite.py", line 53, in get
default_tile = self.get_default_tile(name)
TypeError: get_default_tile() takes exactly 1 argument (2 given)
I only passed one argument to get_default_tile() why does it complain that I passed two?
You're missing a comma after ('/upload', Upload) in the WSGIApplication setup.
use this python code
import jinja2 # html template libary
import os
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
import urllib
import urllib2
import webapp2
from google.appengine.ext import db
from google.appengine.api import urlfetch
class Default_tiles(db.Model):
name = db.StringProperty()
image = db.BlobProperty(default=None)
class MainPage(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render())
class Upload(webapp2.RequestHandler):
def post(self):
# get information from form post upload
image_url = self.request.get('image_url')
image_name = self.request.get('image_name')
# create database entry for uploaded image
default_tile = Default_tiles()
default_tile.name = image_name
default_tile.image = db.Blob(urlfetch.Fetch(image_url).content)
default_tile.put()
self.redirect('/?' + urllib.urlencode({'image_name': image_name}))
class Get_default_tile(webapp2.RequestHandler):
def get_default_tile(self, name):
result = db.GqlQuery("SELECT * FROM Default_tiles WHERE name = :1 LIMIT 1", name).fetch(1)
if (len(result) > 0):
return result[0]
else:
return None
def get(self):
name = self.request.get('image_name')
default_tile = self.get_default_tile(name)
self.response.headers['Content-Type'] = "image/png"
self.response.out.write(default_tile)
app = webapp2.WSGIApplication([('/', MainPage),
('/upload', Upload),
('/default_tile_img', Get_default_tile)],
debug=True)

Integrating Chat with (webapp2 + python 2.7 + Jinja2)

I'm trying to add chat to my site and am integrating some code with my existing code. The chat app works fine on its own when it's all set up in the original main.app file. But when I try to move that same code to a handlers.py file and then setup up routes in routes.py I get errors saying template variables are undefined. Are the two different codes conflicting in the way they render templates? They seem to be using webapp2 differently, i.e. my code renders templates like this:
self.render_template('secure_zone.html', **params)
And the chat app like this:
self.response.out.write(render("main.html",
username=username,
usernameerror=usernameerror,
channel=channelname,
channelerror=channelerror))
Are both acceptable?
Here's my handlers.py file:
Routes are setup in routes.py and added in main.py
"""
import httpagentparser
from boilerplate import models
from boilerplate.lib.basehandler import BaseHandler
from boilerplate.lib.basehandler import user_required
class SecureRequestHandler(BaseHandler):
"""
Only accessible to users that are logged in
"""
#user_required
def get(self, **kwargs):
user_session = self.user
user_session_object = self.auth.store.get_session(self.request)
user_info = models.User.get_by_id(long( self.user_id ))
user_info_object = self.auth.store.user_model.get_by_auth_token(
user_session['user_id'], user_session['token'])
try:
params = {
"user_session" : user_session,
"user_session_object" : user_session_object,
"user_info" : user_info,
"user_info_object" : user_info_object,
"userinfo_logout-url" : self.auth_config['logout_url'],
}
return self.render_template('secure_zone.html', **params)
except (AttributeError, KeyError), e:
return "Secure zone error:" + " %s." % e
Here's the main.py file for the chat app:
import os
import hashlib
import urllib
import logging
import re
import json
import webapp2
import jinja2
from google.appengine.api import channel as channel_api # 'channel' is kind of ambiguous in context
from google.appengine.ext import db
from google.appengine.api import memcache
# This section will eventually get moved to a Handler class
template_dir = os.path.join(
os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(
loader = jinja2.FileSystemLoader(template_dir),
autoescape = True)
def render_str(template, **params):
'''Returns a string of the rendered template'''
t = jinja_env.get_template(template)
return t.render(params)
def render(template, **kw):
'''Render using the template and parameters'''
return(render_str(template, **kw))
# End Handler
class Main(webapp2.RequestHandler):
def get(self):
'''Show connection page'''
return self.render_template("main.html", channel="#udacity")
def post(self):
'''Displays chat UI'''
username = self.request.get('username')
channelname = self.request.get('channel')
usernameerror = ""
if not username:
usernameerror="Please enter a username"
elif not re.compile(r'^[a-zA-Z0-9_-]{3,20}$').match(username):
usernameerror = "Username must consist of 3-20 alphanumeric characters."
elif get_user(username):
usernameerror="Username already in use"
channelerror = ""
if channelname and not re.compile(r'^#[\w]{3,20}$').match(channelname):
channelerror="Channel must consist of 3-20 alpha_numeric characters and start with a #"
if len(usernameerror+channelerror) > 0:
self.response.out.write(render("main.html",
username=username,
usernameerror=usernameerror,
channel=channelname,
channelerror=channelerror))
app = webapp2.WSGIApplication([
('/', Main),
('/communication', Communication),
('/_ah/channel/connected/?', Connect),
('/_ah/channel/disconnected/?', Disconnect)
], debug=True)
The specific error you posted in the comments "Error: 'Main' object has no attribute 'render_template'" is because in your Main handler, you try to return self.render_template. You should be just calling the function like this:
render_template("main.html", channel="#udacity")
Please note that I did not check the rest of your code, so if you run into any other issues, please post the specific errors you get.
It is because your webapp2.RequestHandler do not have the corresponding function "render_template"
you can use a BaseHandler with render_template function added to achieve the template rendering
from google.appengine.ext.webapp import template
class BaseHandler(webapp2.RequestHandler):
def render_template(self, filename, **template_args):
path = os.path.join(os.path.dirname(__file__), 'templates', filename)
self.response.write(template.render(path, template_args))
class Main(BaseHandler):
def get(self):
'''Show connection page'''
return self.render_template("main.html", channel="#udacity")
ref: http://blog.notdot.net/2011/11/Migrating-to-Python-2-7-part-2-Webapp-and-templates
I just started using webapp2 + python 2.7 + Jinja2 few days, and that is the same problem I encountered.
Hope this solution can help you ;)

How to convert from text to PDF using conversion API in GAE?

i'm working on a task that i want to convert text file into PDF one using conversion API that is in GAE , i tried as: https://developers.google.com/appengine/docs/python/conversion/overview
This is the code that i used:
from __future__ import with_statement
from google.appengine.api import files
import cgi, cgitb ; cgitb.enable()
import StringIO
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
import mimetypes
from google.appengine.ext import blobstore
from mimetypes import guess_type
from google.appengine.api import conversion
def mime_type(filename):
return guess_type(filename)[0]
class get(webapp.RequestHandler):
def post(self):
form = cgi.FieldStorage()
file_upload = form['file']
name=file_upload.filename
m=mimetypes.guess_type(name)[0]
data=file_upload.file.read()
buf = StringIO.StringIO()
asset = conversion.Asset("text/plain", data, file_upload.filename)
conversion_obj = conversion.ConversionRequest(asset, "application/pdf")
result = conversion.convert(conversion_obj)
if result.assets:
for asset in result.assets:
buf.write(asset.data)
else:
print "ERROR"
u_file = files.blobstore.create(mime_type="application/pdf",_blobinfo_uploaded_filename="test.pdf")
data=buf.getvalue()
with files.open(u_file, 'a') as f:
f.write(data)
files.finalize(u_file)
blob_key = files.blobstore.get_blob_key(u_file)
blob_info = blobstore.get(blob_key)
name2 = blob_info.filename
self.response.out.write("""<html><br><body style="background-color:#CC9999"><b><font size="5" face="Batang" ><center> <li ><a href="download.py?blob_key=%s" style="color:black">%s
</center></font><hr></body></html>
""" % (str(blob_key),str(name2)))
def main():
application = webapp.WSGIApplication( [(r'/get.py', get)], debug=True)
run_wsgi_app(application)
if __name__ == "__main__":
main()
download.py:
from __future__ import with_statement
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.util import run_wsgi_app
from mimetypes import guess_type
def mime_type(filename):
return guess_type(filename)[0]
class Thumbnailer(blobstore_handlers.BlobstoreDownloadHandler):
def get(self):
blob_key = self.request.get("blob_key")
if blob_key:
blob_info = blobstore.get(blob_key)
if blob_info:
save_as1 = blob_info.filename
type2=mime_type(blob_info.filename)
self.send_blob(blob_info,content_type=type2,save_as=save_as1)
return
def main():
application = webapp.WSGIApplication([
(r'/download.*', Thumbnailer),
], debug=True)
run_wsgi_app(application)
if __name__ == '__main__':
main()
EDIT:i edited the code, and when i try to print buf.getvalue(),i get :failed to load pdf document.
But when i try to open this PDF,i can't open it and the adobe reader gives error immediately that it can't open the file. Sorry i'm still beginner,any help please? Any suggestions are welcome.
Here is my working code sample(it's for Python2.7 runtime though). Good luck!
import os
import StringIO
from google.appengine.api import conversion
from google.appengine.api import files
from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
import jinja2
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja2_env = jinja2.Environment(
loader=jinja2.FileSystemLoader(template_dir))
class MainHandler(webapp.RequestHandler):
def get(self):
tmpl = jinja2_env.get_template('index.jinja2')
self.response.out.write(tmpl.render())
class PostHandler(blobstore_handlers.BlobstoreDownloadHandler):
def post(self):
data = self.request.get('file')
asset = conversion.Asset('text/plain', data, 'test.txt')
conversion_obj = conversion.Conversion(asset, 'application/pdf')
result = conversion.convert(conversion_obj)
buf = StringIO.StringIO()
if result.assets:
for asset in result.assets:
buf.write(asset.data)
else:
raise Exception('Conversion failed.')
u_file = files.blobstore.create(mime_type='application/pdf',
_blobinfo_uploaded_filename='test.pdf')
with files.open(u_file, 'a') as f:
f.write(buf.getvalue())
files.finalize(u_file)
blob_key = files.blobstore.get_blob_key(u_file)
blob_info = blobstore.get(blob_key)
self.send_blob(blob_info)
app = webapp.WSGIApplication([
('/', MainHandler),
('/post_file', PostHandler),
],
debug=True)
Are you sure that your 'data' (retrieved by data=file_upload.file.read()) is correct?
Maybe you can stop using cgi module, and just use a request object that webapp creates for you like:
data = self.request.get('file')
BTW, please don't use private attributes like asset._data, use asset.data instead. Additionally, what the StringIO is for? Have you considered just writing asset.data directly to the opened file?
Update: I think I find the cause.
Just after the conversion, please do as follows:
if result.assets:
for asset in result.assets
buf.write(asset.data)

Resources