I can not download a blob from GAE BlobStore - google-app-engine

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.

Related

Google App Engine WebApp2 template not working

I am learning Google App Engine, and have started with WebApp2 framework + Jinja2 template.
I have written the following code:
Main.py
import webapp2
import os
import jinja2
from google.appengine.ext.webapp import template
from google.appengine.api import users
from google.appengine.ext import ndb
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir))
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self, write(self.render_str(template, **kw))
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hello world!')
class PageOne(Handler):
def get(self):
self.render('pageone.html')
app = webapp2.WSGIApplication([('/', MainHandler),('/pageone', PageOne)], debug=True)
app.yaml
application: tbapp
version: 1
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: /favicon\.ico
static_files: favicon.ico
upload: favicon\.ico
- url: .*
script: main.app
libraries:
- name: webapp2
version: "2.5.2"
- name: jinja2
version: latest
There is also a pageone.html HTML file in templates folder.
Now, when I run the files, the main page is showing Hello world!. But, when I run http://localhost:8080/pageone..... it returns the following error..
File "E:\gae_apps\tbapp\tbapp\main.py", line 50, in get
self.render('pageone.html')
File "E:\gae_apps\tbapp\tbapp\main.py", line 40, in render
self, write(self.render_str(template, **kw))
NameError: global name 'write' is not defined
Can anyone please guide me, what am In doing wrong. I am not able to figure out. TIA
As Amber pointed out, you have a typo in your Handler's render method.
Replace
def render(self, template, **kw):
self, write(self.render_str(template, **kw))
With
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
The error message does give you a hint
NameError: global name 'write' is not defined

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')

serve images using 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)

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)

User Accounts with (Python 2.7 + Webapp2 + Google App Engine + Jinja + NDB + WTForms)

I have been racking my brain for weeks trying to get this authentication module to work under the webapp2 framework using Jinja, NDB and WTForms. I've looked online everywhere and have reached my breaking point and need to reach out to somebody for help. I've been following this tutorial (which is pretty thorough but I think leaves out some important details, especially for a newbie like me):
User Accounts with Webapp2 + Google App Engine
As far as I know I have everything setup correctly but I continually get a 404 - resources can not be found. What could I be doing wrong? Here is my code...
handlers.py:
import webapp2
import sys
from google.appengine.ext import ndb
sys.modules['ndb'] = ndb
import webapp2_extras.appengine.auth.models as auth_models
from google.appengine.api import users
from webapp2_extras import sessions, auth # we'll use auth later on
from webapp2_extras.auth import InvalidAuthIdError
from webapp2_extras.auth import InvalidPasswordError
from wtforms import Form, TextField, PasswordField, validators
from webapp2_extras.appengine.users import login_required
def jinja2_factory(app):
j = jinja2.Jinja2(app)
j.environment.filters.update({
# Set filters. (http://tinyurl.com/jinja2-factory)
# ...
})
j.environment.globals.update({
# Set global variables.
'uri_for': webapp2.uri_for,
# ...
})
return j
def login_required(handler):
def check_login(self, *args, **kwargs):
if not self.user:
return self.redirect_to('login')
else:
return handler(self, *args, **kwargs)
return check_login
class UserAwareHandler(webapp2.RequestHandler):
def dispatch(self):
try:
super(UserAwareHandler, self).dispatch()
finally:
# Save the session after each request
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session_store(self):
return sessions.get_store(request=self.request)
#webapp2.cached_property
def session(self):
return self.session_store.get_session(backend="datastore")
#webapp2.cached_property
def auth(self):
return auth.get_auth(request=self.request)
#webapp2.cached_property
def user(self):
user = self.auth.get_user_by_session()
return user
#webapp2.cached_property
def user_model(self):
user_model, timestamp = self.auth.store.user_model.get_by_auth_token(
self.user['user_id'],
self.user['token']) if self.user else (None, None)
return user_model
#webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(factory=jinja2_factory, app=self.app)
def render_response(self, _template, **context):
ctx = {'user': self.user_model}
ctx.update(context)
rv = self.jinja2.render_template(_template, **ctx)
self.response.write(rv)
class SignupForm(Form):
email = TextField('Email',
[validators.Required(),
validators.Email()])
password = PasswordField('Password',
[validators.Required(),
validators.EqualTo('confirm_password',
message="Passwords must match.")])
password_confirm = PasswordField('Confirm Password',
[validators.Required()])
class SignupHandler(UserAwareHandler):
#Serves up a signup form, creates new users
def get(self):
self.render_response("templates/signup.html", form=SignupForm())
def post(self):
form = SignupForm(self.request.POST)
error = None
if form.validate():
success, info = self.auth.store.user_model.create_user(
"auth:" + form.email.data,
unique_properties=['email'],
email= form.password.data,
password_raw= form.password.data)
if success:
self.auth.get_user_by_password("auth:"+form.email.data,
form.password.data)
return self.redirect_to("index")
else:
error = "That email is already in use." if 'email'\
in user else "Something has gone horrible wrong."
self.render_response("templates/signup.html", form=form, error=error)
class LoginForm(Form):
email = TextField('Email',
[validators.Required(), validators.Email()])
password = PasswordField('Password',
[validators.Required()])
class LoginHandler(UserAwareHandler):
def get(self):
self.render_response("templates/index.html", form=LoginForm())
def post(self):
form = LoginForm(self.request.POST)
error = None
if form.validate():
try:
self.auth.get_user_by_password(
"auth:"+form.email.data,
form.password.data)
return self.redirect_to('secure')
except (auth.InvalidAuthIdError, auth.InvalidPasswordError):
error = "Invalid Email / Password"
self.render_response("templates/login.html", form=form, error=error)
class LogoutHandler(UserAwareHandler):
#Destroy the user session and return them to the login screen.
#login_required
def get(self):
self.auth.unset_session()
self.redirect_to('login')
class IndexHandler(UserAwareHandler):
def get(self):
ctx = {
'title1': "ALAZA",
'title2': "HOA",
'slogan': "A communication tool for the Alazan HOA.",
'message1': """
<p>The whole idea here is to show how to set up a simple static web site
on Google App Engine. I want to create an easy way to host your modest web
site on App Engine. My approach is dead simple. All I use is some boilerplate
code almost anyone can follow. You can have multiple pages and use template
variable features that are part of App Engine's WebApp Framework. Most modest
web sites don't do much more than this. Your certainly free to expand on what
you find here.</p>""",
}
self.render_response('templates/index.html', **ctx)
main.py:
import webapp2
import config
import routes
import sys
from google.appengine.ext import ndb
sys.modules['ndb'] = ndb
import webapp2_extras.appengine.auth.models as auth_models
class AwesomeUser(auth_models.User):
email = ndb.StringProperty()
webapp2_config = {}
webapp2_config['webapp2_extras.sessions'] = {
'secret_key': 'othello',}
webapp2_config['webapp2_extras.auth'] = {
'user_model': AwesomeUser,}
app = webapp2.WSGIApplication(config=config.webapp2_config)
routes.add_routes(app)
routes.py:
import handlers
import webapp2
from webapp2_extras.routes import RedirectRoute
# Using redirect route instead of simple routes since it supports strict_slash
# Simple route: http://webapp-improved.appspot.com/guide/routing.html#simple-routes
# RedirectRoute: http://webapp-improved.appspot.com/api/webapp2_extras/routes.html#webapp2_extras.routes.RedirectRoute
_routes = [
RedirectRoute('templates/login.html', handlers.LoginHandler, name='login'),
RedirectRoute('/templates/logout.html', handlers.LogoutHandler, name='logout'),
RedirectRoute('/templates/index.html', handlers.IndexHandler, name='index'),
RedirectRoute('/templates/signup.html', handlers.SignupHandler, name='signup'),]
def get_routes():
return _routes
def add_routes(app):
if app.debug:
secure_scheme = 'http'
for r in _routes:
app.router.add(r)
app.yaml:
application: alazan-hoa
version: main
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /js
static_dir: js
- url: /images
static_dir: images
- url: /css
static_dir: css
- url: /.*
script: main.app
libraries:
- name: webapp2
version: "2.5.1"
- name: jinja2
version: "2.6"
builtins:
- appstats: on
In your routes.py file, in the RedirectRoute you specify html files, while you should specify paths that are mapped to handler methods and inside them render the html templates.
For example, in your routes.py file you should have something like this:
_routes = [
RedirectRoute('/login', handlers.LoginHandler, name='login'),
RedirectRoute('/logout', handlers.LogoutHandler, name='logout'),
RedirectRoute('/index', handlers.IndexHandler, name='index'),
RedirectRoute('/signup', handlers.SignupHandler, name='signup')
]
You can take a look at Google App Engine Boilerplate for an introduction to Google App Engine development and best practices around it.
Hope this helps!

Resources