I'm new to python and GAE and I've been trying to learn how to work with tasks queues, cron, and datastore for my own project through examples but haven't had much luck at all. I trying to modify the Votelator code from this Google Developers tutorial video on YouTube: http://www.youtube.com/watch?v=AM0ZPO7-lcE which can be seen working here: http://voterlator.appspot.com/
I realized that the code wasn't complete, so I decided to try to figure out what was missing. I made some substitutions (e.g., programming languages are now dairy products). There are a few things that aren't worked out in the tutorial code. For example, the variable LANGUAGES is not specified anywhere. It's not clear to me how the data model pulls the values for languages from the form and uses them as keys.
I can't figure out why it's not working. I left some of the code I tried to make it work in there and commented it out.
Here's the app.yaml:
application: voting
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /static/css
static_dir: static/css
- url: /static/css/sunny
static_dir: static/css/sunny
- url: /static/js
static_dir: static/js
- url: /cron/tally
script: main.app
- url: /.*
script: main.app
Here's the cron.yaml:
cron:
- description: vote tallying worker
url: /cron/tally
schedule: every 1 minutes
This is the queue.yaml
total_storage_limit: 120M
queue:
- name: votes
mode: pull
This is the main.py
import webapp2
from google.appengine.ext import db
from google.appengine.api import taskqueue
import os
import jinja2
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class Tally(db.Model):
"""Counting model"""
count = db.IntegerProperty(default=0, required=True)
#key_name = ['Milk', 'Butter', 'Cheese'] #added
#key_name = db.StringProperty(choices=set(['Milk', 'Butter', 'Cheese'])) #added
cls = ['Milk', 'Butter', 'Cheese'] #added
@classmethod
def increment_by(cls, key_name, count):
"""Increases a tally's count. Should be run in a transaction."One tally for each language"""
"""The key_name is going to be the language name"""
"""There's a convenience method there that actually will update the count"""
tally = cls.get_by_key_name(key_name)
if tally is None:
tally = cls(key_name=key_name)
tally.count += count
tally.put()
#db.run_in_transaction(increment_by, key_name, count) #added
#db.run_in_transaction(cls, key_name, count) #added
#db.run_in_transaction(Tally.increment_by, cls, count) #added
class VoteHandler(webapp2.RequestHandler):
"""Handles adding of vote tasks"""
def get(self):
"""Displays the voting form"""
tally_query = Tally.all() #added
#tally_query = Tally.all(key_name) #added
tallies = tally_query.fetch(3) #added
urla = '_ah/admin/'
url_admin = 'Admin'
urlvh = '/'
url_votehand = 'Votes'
ugliest = self.request.get('ugliest')
template_values = {
'tallies': tallies, #added
'ugliest': ugliest, #added
'url_admin': url_admin,
'urla': urla,
'urlvh': urlvh,
'url_votehand': url_votehand,
}
template = jinja_environment.get_template('vote_handler.html')
self.response.out.write(template.render(template_values))
def post(self):
"""Adds to the votes queue if ugliest is valid. """
LANGUAGES = ['Milk', 'Butter', 'Cheese'] #added: This is just a guess
ugliest = self.request.get('ugliest')
if ugliest and ugliest in LANGUAGES: ### No variable specified for LANGUAGES
q = taskqueue.Queue('votes')
q.add(taskqueue.Task(payload=ugliest, method='PULL'))
self.redirect('/')
#db.run_in_transaction(Tally.increment_by(cls, key_name, count)) #added
class TallyHandler(webapp2.RequestHandler):
def post(self):
"""Leases vote tasks, accumulates tallies and stores them"""
q = taskqueue.Queue('votes')
# Keep leasing tasks in a loop.
while True:
tasks = q.lease_tasks(300, 1000)
if not tasks:
return
# accumulate tallies in memory
tallies = {}
for t in tasks:
tallies[t.payload] = tallies.get(t.payload, 0) + 1
self.store_tallies(tallies)
q.delete_tasks(tasks)
app = webapp2.WSGIApplication([('/', VoteHandler),
('/cron/tally', TallyHandler)], #called from cron, pulls votes from the queue and updating tallies
debug=True)
def main():
app.run()
if __name__ == "__main__":
main()
This is the code for the form in the vote_handler.html:
<form action="/" method="post">
<input type="radio" name="ugliest" value="Milk" /> Milk<br>
<input type="radio" name="ugliest" value="Butter" /> Butter<br>
<input type="radio" name="ugliest" value="Cheese" /> Cheese
<br>
<div>
<input type="submit" value="Submit">
</div>
</form>
<div class="commentary">
{% for tally in tallies %}
{{ tally.count }}
{% endfor %}
</div>
I tried to get it to display the results just below the form.
What ends up happening is that the form adds tasks to the queue and there's a Task kind in the Datastore but it doesn't have any entities in it. I have no clue what is wrong.