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...
Related
I am trying to get my ancestor query to work but I keep getting this error:
BadQueryError: Parse Error: Identifier is a reserved keyword at symbol
ANCESTOR
at this line:
TweepleKey(twitter_handle))
I was following Using the Datastore tutorial (which works) but when I tried to apply the concepts of ancestor query to my code (see below) it keeps producing the above mentioned error. Where did I go wrong?
import cgi
import urllib
import webapp2
import cgi
from google.appengine.ext import db
# defines a data model for a geotweet
# GeoTweet model has 1 property: twitter_handle
class GeoTweet(db.Model):
twitter_handle = db.StringProperty()
date = db.DateTimeProperty(auto_now_add=True)
def TweepleKey(twitter_handle=None):
# Constructs a Datastore key for a TweepleStore entity with twitter_handle
return db.Key.from_path('TweepleStore', twitter_handle or 'default_handle')
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.out.write("""<html><body>""")
twitter_handle = self.request.get('twitter_handle')
tweeple = db.GqlQuery("SELECT * "
"FROM GeoTweet "
"WHERE ANCESTOR = :1 "
"ORDER BY date DESC LIMIT 10",
TweepleKey(twitter_handle))
for t in tweeple:
if t.twitter_handle:
self.out.write('<b>Found %s. Saved on %s.</b>' % (t.twitter_handle, t.date))
else:
self.out.write('<b>%s was not found!' % twitter_handle)
self.response.out.write("""<form action="/search" method="post">
<div><textarea name="twitter_handle" rows="1" cols="20">#example</textarea>
<div><input type="submit" value="Find"></div>
</form>
</body>
</html>""")
class TweepleStore(webapp2.RequestHandler):
def post(self):
twitter_name = self.request.get('twitter_handle')
geotweet = GeoTweet(parent=TweepleKey(twitter_name))
geotweet.twitter_handle = twitter_name
geotweet.put()
self.redirect('/?' + urllib.urlencode({'twitter_name': twitter_name}))
app = webapp2.WSGIApplication([('/', MainPage),
('/search', TweepleStore)], debug=True)
The GQL reference says to use WHERE ANCESTOR IS.
I am having difficulties in storing and then retrieving the blobstore key. It looks like I am able to get the database row key # instead of the blob key#....
1) I am not sure how to store the key
2) Also, I am not sure how the data currently gets stored into the UserPhoto datastructure
set up
3) How do I retrieve the Blob's key related to the current user, so I can display a link to i?
any help would be greatly appreciated.
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext import db
import urllib
class UserPhoto(db.Model):
user = db.StringProperty()
user1 = db.EmailProperty()
blob_prop = blobstore.BlobKey
blob_key = blobstore.BlobReferenceProperty()
class MainPage(webapp.RequestHandler):
def get(self):
user = users.get_current_user()
upload_url = blobstore.create_upload_url('/upload')
existing_data = "<br>"
if user:
data = UserPhoto.all()
#filter data by user e-mail
results = data.filter("user1 = ", user.email())
for dt in results:
existing_data +='<a href="/serve/%s' % dt.key() + '">'
existing_data += '%s' % dt.key() + '<br>'
self.response.out.write(
'<div align=center>Hello %s <a align="center" href="%s">Sign out</a><br>Is administrator: %s' %
(user.nickname(), users.create_logout_url("/"), users.is_current_user_admin())
+'<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url+
"""<br>Upload File: <input type="file" name="file"><br> <input type="submit"
name="submit" value="Submit"> </form>
<br>"""+existing_data + "</div>"
)
#the code below is used for testing...purposes only...
for b in blobstore.BlobInfo.all():
self.response.out.write('<li>' + str(b.filename) + '')
else:
self.redirect(users.create_login_url(self.request.uri))
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 = users.get_current_user()
if user:
data = UserPhoto()
data.user1 = users.get_current_user().email()
data.blob_key = str(blob_info.key())
# data.user2[0] = self.get_uploads()
data.blob_prop = blob_info.key()
data.put()
#self.redirect('/serve/%s' % blob_info.key())
self.redirect('/')
class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, photo_key):
blob_key = str(urllib.unquote(photo_key))
if not blobstore.get(photo_key):
self.error(404)
else:
#self.send_blob(photo_key)
#self.send_blob('/serve/%s' % photo_key)
self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)
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)
application = webapp.WSGIApplication([('/', MainPage),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler),
('/view_photo/([^/]+)?', ViewPhotoHandler)
],debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
You're asking for the UserPhoto entity key when you construct the output, not the blobstore reference within that entity. It should be:
existing_data +='<a href="/serve/%s">' % dt.blob_key
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 have a small app that has a form that grabs data about a new hire, emails people about it, and stores the data for future use. Everything is working fine, but I can't seem to find info on using djangoforms and check boxes. These are obviously a boolean value, but if I add a db.Boolean value to my db.Model class, and then had it to djangoforms.ModelForm class to generate it, nothing appears. I added it to my db>model, it creates a record default to false, but there is no way to modify from the form. Also,db.Text doesn't produce a fiel either. I am probably not being clear enough here, due to the fact this is my first GAE and Django project. Code is below
import cgi
import wsgiref.handlers
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.api import mail
from google.appengine.ext.db import djangoforms
class Item(db.Model):
first_name = db.StringProperty()
last_name = db.StringProperty()
goes_by = db.StringProperty()
Studio = db.StringProperty()
Discipline = db.StringProperty()
position = db.StringProperty()
level = db.StringProperty(default='choice', choices=['choice', 'choice',
'choice', 'choice', 'choice', 'choice'])
start_date = db.DateTimeProperty()
buddy_name = db.StringProperty()
past_employee = bool()
email = db.EmailProperty()
cell_phone = db.PhoneNumberProperty()
phone = db.PhoneNumberProperty()
hire_type = db.StringProperty(default='Full Time',choices=[
'Temp', 'Intern', 'Contract', 'Full Time'])
seating_location = db.StringProperty()
additional_comments = db.Text()
entry_time = db.DateTimeProperty(auto_now_add=True)
added_by = db.UserProperty()
class ItemForm(djangoforms.ModelForm):
class Meta:
model = Item
exclude = ['added_by']
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write('<html><body><head><link type="text/css" rel="stylesheet" href="/stylesheets/form.css"></head>'
'<div id=header><div id="logo><img src="/img/placeimg.gif"></div><div id ="headertxt"><h2>Place New Hire Portal</h2>'
'<p>Please filll out this form as accurately as possible, this information is used to create employee files and to setup IS equipment</div> '
'</div><div id="contain">'
'<form method="POST" '
'action="/">'
'<table>')
# This generates our fields and writes it in the response
self.response.out.write(ItemForm())
self.response.out.write('</table>'
'<input type="submit">'
'</form></div></body></html>')
def post(self):
data = ItemForm(data=self.request.POST)
if data.is_valid():
# Save the data, and redirect to the view page
entity = data.save(commit=False)
entity.added_by = users.get_current_user()
entity.put()
self.redirect('/items.html')
mailing_address = ("person#place.com")
sender_address = ("person#place.com")
subject = "A new hire has been made - Please begin Process"
body = ("""
The Following Person is scheduled to start at place on :
%s %s - %s \ %s - %s - %s
Please find the orientation template attached. In order to be sure all employees are oriented in the same way
please be sure to cover the items listed under your name.
In addition, afer the completion of your session, please escort the new hire to the next session and makle introductions. This will
ensure that the schedule continues in order.
Buddy, thank you very much for being a buddy to %s, Your time and lunch expenses should be charged to your Studio Operations number. Thank you
very much for helping %s with their transiton to Place."""
%(entity.first_name, entity.last_name, entity.Studio, entity.Discipline, entity.seating_location,
entity.buddy_name, entity.first_name, entity.first_name))
mail.send_mail(sender_address, mailing_address, subject, body)
else:
# Reprint the form
self.response.out.write('<html><body>'
'<form method="POST" '
'action="/">'
'<table>')
self.response.out.write(data)
self.response.out.write('</table>'
'<input type="submit">'
'</form></body></html>')
class ItemPage(webapp.RequestHandler):
def get(self):
self.response.out.write('</br></br>Return to Form Entry</br></br>')
query = db.GqlQuery("SELECT * FROM Item ORDER BY first_name")
for item in query:
self.response.out.write('Edit - ' %
item.key().id())
self.response.out.write("%s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s </br>"%
(item.first_name, item.last_name, item.goes_by, item.Studio, item.Discipline, item.position,
item.level, item.start_date, item.past_employee, item.cell_phone, item.seating_location,
item.additional_comments, item.email, item.phone, item.hire_type))
class EditPage(webapp.RequestHandler):
def get(self):
id = int(self.request.get('id'))
item = Item.get(db.Key.from_path('Item', id))
self.response.out.write('<html><body>'
'<form method="POST" '
'action="/edit">'
'<table>')
self.response.out.write(ItemForm(instance=item))
self.response.out.write('</table>'
'<input type="hidden" name="_id" value="%s">'
'<input type="submit">'
'</form></body></html>' % id)
def post(self):
id = int(self.request.get('_id'))
item = Item.get(db.Key.from_path('Item', id))
data = ItemForm(data=self.request.POST, instance=item)
if data.is_valid():
# Save the data, and redirect to the view page
entity = data.save(commit=False)
entity.added_by = users.get_current_user()
entity.put()
self.redirect('/items.html')
else:
# Reprint the form
self.response.out.write('<html><body>'
'<form method="POST" '
'action="/edit">'
'<table>')
self.response.out.write(data)
self.response.out.write('</table>'
'<input type="hidden" name="_id" value="%s">'
'<input type="submit">'
'</form></body></html>' % id)
def main():
application = webapp.WSGIApplication(
[('/', MainPage),
('/edit', EditPage),
('/items.html', ItemPage),
],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__=="__main__":
main()
Wobble answered it for me
should be TextProperty and BooleanProperty. db.Text is just an alias to datastore_types.Text, not a Property subclass, and db.Boolean should raise an exception as far as I can see
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()