I am trying to display an uploaded blob image. It seems to be storing ok, but won't display on the html template when called. Even seems to be showing up in the logging. When looking at other examples, the only real difference I see is you have to iterate over a list, but really just want to pull only one picture. Any advice you can give is greatly appreciated. -Thanks
Handlers:
class PictureHandler(BaseHandler2):
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'])
user = self.session.get('user')
uploads = db.GqlQuery("SELECT * FROM UserPictureUpload WHERE user =:1 ORDER BY created DESC", user_info.username).get()
upload_url = blobstore.create_upload_url('/upload')
params = {
'upload_url': upload_url,
'user': user_info.username,
'uploads': uploads
}
return self.render_template('picture.html', **params)
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler, BaseHandler2):
def post(self):
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'])
user = self.session.get('user')
title = self.request.get('title')
pic = self.request.get("picfile")
if pic:
picture = db.Blob(pic)
upload = UserPictureUpload(title = title, picture=picture, user=user_info.username)
upload.put()
self.redirect('/settings/picture')
class ViewHandler(blobstore_handlers.BlobstoreDownloadHandler, BaseHandler2):
def get(self):
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'])
user = self.session.get('user')
upload_key_str = self.request.params.get('key')
if upload_key_str:
upload = db.get(upload_key_str)
if upload:
logging.info('** Upload Found** -- %s' % upload.picture)
self.send_blob(upload.picture)
if not upload_key_str:
self.error(404)
return
Routing:
RedirectRoute('/settings/picture', handlers.PictureHandler, name='picture', strict_slash=True),
RedirectRoute('/upload', handlers.UploadHandler, name='upload', strict_slash=True),
RedirectRoute('/view', handlers.ViewHandler, name='view', strict_slash=True)
Html:
<form action="{{ upload_url }}" method="post" enctype="multipart/form-data">
<label for="title">Title:</label>
<input type="text" id="title" name="title" /><br />
<label for="upload">File:</label>
<input type="file" id="upload" name="picfile" /><br />
<input type="submit" value="Upload Picture" />
</form>
<br />
<img src='/view?key={{uploads.key()}}' alt='no image'/></img>
App Engine Log:
INFO 2013-07-30 16:11:20,946 handlers.py:875] ** Upload Found** -- Content-Type: image/jpeg
Content-Length: 775702
Content-MD5: NWE0NGM3YmE1YmJlNGVjODY3MjMzZDY3ZTQ4MDY4NDg=
content-disposition: form-data; name="picfile"; filename="Jellyfish.jpg"
X-AppEngine-Upload-Creation: 2013-07-29 15:41:00.481000
INFO 2013-07-30 11:11:21,005 server.py:584] default: "GET /view?key=ag5kZXZ-c2FuZGVuZ2luZXIeCxIRVXNlclBpY3R1cmVVcGxvYWQYgICAgJjxtgsM HTTP/1.1" 200 -
It looks like you are uploading the blob in blobstore but creating a key from your post upload handler and storing it as another blob on picture property instead of getting the blobkey from the uploaded blobinfo which from here: https://developers.google.com/appengine/docs/python/tools/webapp/blobstorehandlers
you can get with
upload = self.get_uploads()[0]
picture=upload.key()
then that's what you put on your send_blob.
Related
Can't understand, why this code doesn't work, i was trying to understand, but i'm only learning Flask&Py, help me please:
Flask:
#freepylib.route('/register', methods=['POST', 'GET'])
def signup_user():
if request.method == "POST":
username, useremail, userpasswd=request.form['name'], request.form['email'], request.form['password']
reg = Users(uname=username, useremail=useremail, upasswrd=userpasswd)
try:
mydb.session.add(reg)
mydb.session.commit()
token = reg.get_token()
return {'access_token': token}
except Exception as e:
return str(e)
else:
return render_template("register.html")
HTML code:
<form method="POST" name="reg" id="reg">
<input type ="text" class ="fadeIn second" name ="name" placeholder="name">
<input type="text" class="fadeIn second" name="email" placeholder="email">
<input type="text" class="fadeIn third" name="password" placeholder="password">
<input type="submit" name="subm" class="fadeIn fourth" value="Sign Up">
</form>
Error:
(pymysql.err.IntegrityError) (1048, "Column 'uname' cannot be null") [SQL: INSERT INTO `PFL_USERS` (uname, email, upasswrd) VALUES (%(uname)s, %(email)s, %(upasswrd)s)] [parameters: {'uname': None, 'email': None, 'upasswrd': None}] (Background on this error at: http://sqlalche.me/e/13/gkpj)
I think the problem is in your Users class, in the __init__. The kwargs need to match up with how you're calling the constructor from your app code.
For example, changing it to this should help:
def __init__(self, **kwargs):
self.uname = kwargs.get('uname')
self.email = kwargs.get('useremail')
self.upasswrd = kwargs.get('upasswrd')
Special thanks to #ChrisSears, you make my day
Problem was in class, which i forget to add(i'm really sorry)
So, i'll describe:
reg = Users(uname=username, email=useremail, upasswrd=hash_password(userpasswd))
Using this, i've transfer data into Class Users:
def __init__(self, **kwargs):
self.uname = kwargs.get('name')
self.email = kwargs.get('email')
self.upasswrd = kwargs.get('password')
As we can see, name of variables is not correct, so there is the problem, it should be like this:
def __init__(self, **kwargs):
self.uname = kwargs.get('uname')
self.email = kwargs.get('email')
self.upasswrd = kwargs.get('upasswrd')
I'm creating a dropbox service using BlobStore, however I can't find a good way to implement the file download option from my Django HTML template.
Here is my app.yaml
application: my_application
version: 1
runtime: python27
api_version: 1
threadsafe: false
handlers:
- url: /favicon\.ico
static_files: favicon.ico
upload: /favicon\.ico
- url: (/.*)*
script: main.app
libraries:
- name: django
version: latest
Here is the main.py
#!/usr/bin/env python
from django.core.management import setup_environ
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext import blobstore
from google.appengine.ext.blobstore import BlobInfo
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp import util
import django
import webapp2
import wsgiref.handlers
class UserUpload(db.Model):
blob_key = blobstore.BlobReferenceProperty(required=True)
user = db.UserProperty(required=True)
user_id = db.StringProperty(required=True)
creation = db.DateTimeProperty(required=True, auto_now_add=True)
filename = db.StringProperty()
content_type = db.StringProperty()
size = db.IntegerProperty()
MD5 = db.StringProperty()
# Start Dumpbox login
class MainPage(webapp2.RequestHandler):
#util.login_required
def get(self):
logout_url = users.create_logout_url('/')
upload_url = blobstore.create_upload_url('/upload')
user = users.get_current_user()
q = UserUpload.all()
q.filter('user_id =', users.get_current_user().user_id())
q.order('-creation')
if user:
html = template.render('templates/header.html', {'title': 'Dumpbox', 'nickname': user.nickname(), 'url': upload_url})
html = html + template.render('templates/table.html', { 'file_name': 'File Name',
'content_type': 'Content Type',
'size': 'Size',
'timestamp': 'Creation Date',
'q': q
})
html = html + template.render('templates/footer.html', {'logout_link': logout_url})
self.response.out.write(html)
else:
self.redirect(users.create_login_url(self.request.uri))
class LogoutHandler(webapp2.RequestHandler):
def get(self):
self.auth.unset_session()
self.redirect(self.uri_for('home'))
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]
user_upload = UserUpload( user=users.get_current_user(),
user_id=users.get_current_user().user_id(),
blob_key=blob_info.key(),
filename=blob_info.filename,
content_type=blob_info.content_type,
size=blob_info.size,
creation=blob_info.creation,
MD5=blob_info.md5_hash
)
db.put(user_upload)
self.redirect('/')
class DownloadHandler(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([('/', MainPage),('/upload', UploadHandler),('/download([^/]+)?', DownloadHandler)],debug=True)
wsgiref.handlers.CGIHandler().run(app)
def main():
run_wsgi_app(app)
if __name__ == '__main__':
main()
The Django template uses a table with a checkbox to select file to be downloaded, but I can't find a good way to implement it.
How can tick the checkbox and submit a form to download a blobstore file?
<form method="GET" action="">
<div id="table-wrapper">
<div id="table-scroll">
<table id="file_table" class="display" style="width:100%">
<tr>
<th style="width:10px"><input type="checkbox" onclick="checkAll(this)"/></th>
<th>{{file_name}}</th>
<th>{{content_type}}</th>
<th>{{size}}</th>
<th>{{timestamp}}</th>
</tr>
{% for file in q %}
{% if file.size > 0 %}
<tr>
<td><input id="{{file.blob_key}}" type="checkbox"/></td>
<td>{{file.filename}}</td>
<td>{{file.content_type}}</td>
<td>{{file.size}} Bytes</td>
<td>{{file.creation}}</td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
</div>
<p><input type="submit" value="Download"></p>
</form>
Appreciate any help.
Here's my solution:
In your template change to line
<td>{{file.filename}}</td>
into
<td>{{file.filename}}</td>
In your views add two method:
def download(request,client):
if 'key' in request.GET:
blob_key_str = request.GET['key']
if not blob_key_str:
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
blob_key = str(urllib.unquote(blob_key_str))
blob = blobstore.BlobInfo.get(blob_key)
try:
return send_blob(blob, save_as=True)
except ValueError, error:
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
and
import cgi
import logging
import urllib
def send_blob(blob_key_or_info, content_type=None, save_as=None):
CONTENT_DISPOSITION_FORMAT = 'attachment; filename="%s"'
if isinstance(blob_key_or_info, blobstore.BlobInfo):
blob_key = blob_key_or_info.key()
blob_info = blob_key_or_info
else:
blob_key = blob_key_or_info
blob_info = None
logging.debug(blob_info)
response = HttpResponse()
response[blobstore.BLOB_KEY_HEADER] = str(blob_key)
if content_type:
if isinstance(content_type, unicode):
content_type = content_type.encode('utf-8')
response['Content-Type'] = content_type
else:
del response['Content-Type']
def send_attachment(filename):
if isinstance(filename, unicode):
filename = filename.encode('utf-8')
response['Content-Disposition'] = (CONTENT_DISPOSITION_FORMAT % filename)
if save_as:
if isinstance(save_as, basestring):
send_attachment(save_as)
elif blob_info and save_as is True:
send_attachment(blob_info.filename)
else:
if not blob_info:
raise ValueError('The specified file is not found.')
else:
raise ValueError(
'Unexpected value for the name in which file is '
'expected to be downloaded')
return response
Change this code according to your needs :)
I'm working though the GAE Tutorial and I'm getting the following error.
File "/Users/cparrish/bin/guestbook/guestbook.py", line 62, in get
for greeting in greetings:
NameError: global name 'greetings' is not defined
So I think the problem is here somewhere.
greetings_query = Greeting.query(
ancestor = guestbook_key(guestbook_name)).order(-Greeting.date)
greeetings = greetings_query.fetch(10)
for greeting in greetings:
if greeting.author:
self.response.write(
'<b>%s</b> wrote:' % greeting.author.nickname())
Which are lines 58 - 66
So I'm wondering if anyone else can see what I'm apparently missing here.
Full code base below.
import cgi
import urllib
from google.appengine.api import users
from google.appengine.ext import ndb
import webapp2
MAIN_PAGE_FOOTER_TEMPLATE = """\
<form action="/sign?%s" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
<hr>
<form>Guestbook name:
<input value="%s" name="guestbook_name">
<input type="submit" value="switch">
</from>
%s
</body>
</html>
"""
DEFAULT_GUESTBOOK_NAME = 'default_guestbook'
# We set a parent key on the 'Greetings' to ensure that they are all in the same
# entity group. Queries across the signle entity group will be consistent.
# However, the write rate should be limited to -1/second.
def guestbook_key(guestbook_name="DEFAULT_GUESTBOOK_NAME"):
""" Constructs a Datastore key for a Guestbook entity with guestbook_name. """
return ndb.Key('Guestbook', guestbook_name)
class Greeting(ndb.Model):
"""Models an individual Guestbook entry with author, content, and date. """
author = ndb.UserProperty()
content = ndb.StringProperty( indexed = False )
date = ndb.DateTimeProperty( auto_now_add = True )
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.write('<html><body>')
guestbook_name = self.request.get('guestbook_name', DEFAULT_GUESTBOOK_NAME)
# Ancestor Queries, as shown here, are strongly consisten with the High
# Replication Datastore. Queries that span entity groups are eventually
# consisten. If we omitted the ancestor from this query there would be
# a slight chance that Greetings that had just been written would not
# show up in a query.
greetings_query = Greeting.query(
ancestor = guestbook_key(guestbook_name)).order(-Greeting.date)
greeetings = greetings_query.fetch(10)
for greeting in greetings:
if greeting.author:
self.response.write(
'<b>%s</b> wrote:' % greeting.author.nickname())
else:
self.response.write('An anonymous person wrote:')
self.response.write('<blockquote>%s</blockquote' %
cgi.escape(greeting.content))
if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = 'Logout'
else:
url = users.create_login_url(self.request.uri)
url_linktext = 'Login'
# Write the submission form and the footer of the page
sign_query_parms = urllib.urlencode({'guestbook_name': guestbook_name})
self.response.write(MAIN_PAGE_FOOTER_TEMPLATE % (sign_query_parms, cgi.escape(guestbook_name), url, url_linktext))
class Guestbook(webapp2.RequestHandler):
def post(self):
# We set the same parent key on the 'Greeting' to ensure each getting
# is in the same entity group. Queries across the single entity group
# will be consistent. However, the write reate to a sing entity groupo
# should be limited to ~1/second.
guestbook_name = self.request.get('guestbook_name',
DEFAULT_GUESTBOOK_NAME)
greeting = Greeting(parent=guestbook_key(guestbook_name))
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get('content')
greeting.put()
query_params = {'guestbook_name': guestbook_name}
self.redirect('/?' + urllib.urlencode(query_params))
application = webapp2.WSGIApplication([
('/', MainPage),
('/sign', Guestbook),
], debug=True)
There are three e's in your assignment of greeetings.
greeetings = greetings_query.fetch(10)
for greeting in greetings:
One of these es is not like the others, one of these es just doesn't belong...
I'm trying to understand how to edit or update a model. I have tried several scenarios which sometimes give an error message: 405 Method Not Allowed - The method POST is not allowed for this resource. Below is my code:
The Python Models:
import os
import webapp2
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.ext.webapp import template
class MessageModel(db.Model):
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
class Message(webapp2.RequestHandler):
def get(self):
doRender(self,'message.htm')
def post(self):
m = MessageModel()
m.content = self.request.get('content')
m.put()
self.redirect('/view')
class View(webapp2.RequestHandler):
def get(self):
que = db.Query(MessageModel)
messageview_list = que.fetch(999)
doRender(self,
'view.htm',
{'messageview_list': messageview_list })
class Edit(webapp2.RequestHandler):
def get(self):
doRender(self,'edit.htm')
def post(self):
updated_content = self.request.get('content')
content_query = db.GqlQuery("SELECT * "
"FROM MessageModel "
"ORDER BY date DESC LIMIT 1")
messageview_list = content_query.fetch(1)
m = MessageModel()
m.content = self.request.get(updated_content)
m.put()
doRender(self,
'edit.htm',
{'messageview_list': messageview_list })
class Main(webapp2.RequestHandler):
def get(self):
doRender(self,'index.htm')
def doRender(handler, tname = 'index.htm', values = { }):
temp = os.path.join(
os.path.dirname(__file__),
'templates/' + tname)
if not os.path.isfile(temp):
return False
newval = dict(values)
newval['path'] = handler.request.path
outstr = template.render(temp, newval)
handler.response.out.write(outstr)
return True
app = webapp2.WSGIApplication([('/', Main),
('/message', Message),
('/view', View),
('/edit', Edit)],
debug=True)
The HTML Form:
{% for messageview in messageview_list %}
<form method="post" action="/edit">
<p>
<textarea name="message" rows="3" cols="60" MAXLENGTH=60>
{{ messageview.content }}</textarea>
<br>
<input type="submit" value="Update"/>
</p>
</form>
{% ifnotequal error None %}
<p>
{{ error }}
</p>
{% endifnotequal %}
{% endfor %}
I am assuming the indentation is due to copy/paste, but make sure that the post() and get() functions are actually indented inside of your class.
In your form, you have <textarea name="message" rows="3" cols="60" MAXLENGTH=60>, but in your def post() you use updated_content = self.request.get('content'), which is looking for the content keyword in the request. Also, your edit doesn't look like it is doing what you want it to do. In order to edit an entity, the basic outline of the process is 1.) Retrieve the entity (so do as you do, query using some parameter); 2.) Modify the properties of the entity however you want; and 3.) put() the entity back in the datastore.
From your code, it looks like you are retrieving the last entity entered into the datastore, but then creating a new model instead of editing that one (assuming that is what you want to do - not quite sure if that is accurate :) ). If you are looking to modify the entity that is returned, this should work:
def post(self):
updated_content = self.request.get('message')
content_query = db.GqlQuery("SELECT * "
"FROM MessageModel "
"ORDER BY date DESC LIMIT 1")
# Your query will always return just one entity (due to the LIMIT),
# but you can use get() here instead of fetch(1)
latest_model = content_query.get()
# Update the model's content property
latest_model.content = updated_content
latest_model.put()
# Assuming you want to output that model, you'd output it now
doRender(self,
'edit.htm',
{'messageview_list': latest_model })
I read the tutorial and all the sources I could find about displaying an image saved in datastore and still I could not make it work. I appreciate any help. This is my previous question.
The code below, for /displayimage shows broken link for the image; and for /image it gives BadKeyError: Invalid string key . According to Nick Johnson reply here I must be passing an empty string for img_id but logging.info in /display image shows this key: (((result.key():)))) agpkZXZ-dGluZy0xcg8LEghIb21lUGFnZRjOCAw. Thanks for your help.
class HomePage(db.Model):
thumbnail = db.BlobProperty()
firm_name = db.StringProperty()
class ImageUpload(webapp.RequestHandler):
def get(self):
...
self.response.out.write("""
<form action="/imagesave" enctype="multipart/form-data" method="post">
<div><label>firm name:</label> <input type="text" name="firm_name" size=40></div>
<div><input type="file" name="img" /></div>
<div><input type="submit" value="Upload image"></div>
</form>
""")
class ImageSave(webapp.RequestHandler):
def post(self):
homepage = HomePage()
thumbnail = self.request.get("img")
firm_name = self.request.get("firm_name")
homepage.thumbnail = db.Blob(thumbnail)
homepage.firm_name = firm_name
homepage.put()
self.redirect("/imageupload")
class ImageResize(webapp.RequestHandler):
def post(self):
q = HomepageImage.all()
q.filter("firm_name", "mta")
qTable = q.get()
if qTable:
qTable.thumbnail = db.Blob(images.resize(self.request.get("img"), 32, 32))
db.put(qTable)
else:
self.response.out.write("""firm not found""")
self.redirect("/imageupload")
class DisplayImage(webapp.RequestHandler):
def get(self):
...
query = HomePage.all()
query.filter("firm_name", "mta")
result = query.get()
self.response.out.write("""firm name: %s""" % result.firm_name)
#self.response.out.write("""<img src="img?img_id=%s"></img>""" %
#chenged this line as systempuntoout's comment to:
self.response.out.write("""<img src="/image?img_id=%s"></img>""" %
result.key())
#but I still get the same error
class Image(webapp.RequestHandler):
def get(self):
...
#I am adding the next line to show that "img_id" is an empty string.
#why "img_id" empty here?
img_id = self.request.get("img_id")
logging.info("""**************************img_id: %s**************************""" % img_id)
#**************************img_id: **************************
homepage = db.get(self.request.get("img_id"))
if homepage.thumbnail:
self.response.headers['Content-Type'] = "image/jpg"
self.response.out.write(homepage.thumbnail)
else:
self.response.out.write("no image")
application = webapp.WSGIApplication(
[
("/imageresize",ImageResize),
("/imageupload", ImageUpload),
("/displayimage", DisplayImage),
("/imagesave", ImageSave),
("/image", Image),
],
debug=True
)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
You are pointing the image source to a not defined wrong img route .
The correct link should point to /image like this:
<img src="/image?img_id=%s"></img>
I've tested your code with my correction and it works nicely:
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
import logging
class HomePage(db.Model):
thumbnail = db.BlobProperty()
firm_name = db.StringProperty()
class ImageUpload(webapp.RequestHandler):
def get(self):
self.response.out.write("""
<form action="/imagesave" enctype="multipart/form-data" method="post">
<div><label>firm name:</label> <input type="text" name="firm_name" size=40></div>
<div><input type="file" name="img" /></div>
<div><input type="submit" value="Upload image"></div>
</form>
""")
class ImageSave(webapp.RequestHandler):
def post(self):
homepage = HomePage()
thumbnail = self.request.get("img")
firm_name = self.request.get("firm_name")
homepage.thumbnail = db.Blob(thumbnail)
homepage.firm_name = firm_name
homepage.put()
self.redirect("/imageupload")
class ImageResize(webapp.RequestHandler):
def post(self):
q = HomepageImage.all()
q.filter("firm_name", "mta")
qTable = q.get()
if qTable:
qTable.thumbnail = db.Blob(images.resize(self.request.get("img"), 32, 32))
db.put(qTable)
else:
self.response.out.write("""firm not found""")
self.redirect("/imageupload")
class DisplayImage(webapp.RequestHandler):
def get(self):
query = HomePage.all()
query.filter("firm_name", "mta")
result = query.get()
self.response.out.write("""firm name: %s""" % result.firm_name)
self.response.out.write("""<img src="/image?img_id=%s"></img>""" %
result.key())
class Image(webapp.RequestHandler):
def get(self):
img_id = self.request.get("img_id")
logging.info("""**************************img_id: %s**************************""" % img_id)
homepage = db.get(self.request.get("img_id"))
if homepage.thumbnail:
self.response.headers['Content-Type'] = "image/jpg"
self.response.out.write(homepage.thumbnail)
else:
self.response.out.write("no image")
application = webapp.WSGIApplication(
[
("/imageresize",ImageResize),
("/imageupload", ImageUpload),
("/displayimage", DisplayImage),
("/imagesave", ImageSave),
("/image", Image),
],
debug=True
)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()