views:

305

answers:

3

I'm attempting my first google app engine project – a simple player stats database for a sports team I'm involved with. Given this model:

class Player(db.Model):
    """ Represents a player in the club. """

    first_name = db.StringProperty()
    surname = db.StringProperty()
    gender = db.StringProperty()

I want to make a basic web interface for creating and modifying players. My code structure looks something like this:

class PlayersPage(webapp.RequestHandler):
    def get(self):
        # Get all the current players, and store the list.
        # We need to store the list so that we can update
        # if necessary in post().
        self.shown_players = list(Player.all())

        # omitted: html-building using django template

This code produces a very basic HTML page consisting of a form and a table. The table has one row for each Player, looking like something like this:

  <tr>
    <td><input type=text name="first_name0" value="Test"></td>
    <td><input type=text name="surname0" value="Guy"></td>
    <td><select name="gender0">
        <option value="Male" selected>Male</option>
        <option value="Female" >Female</option>
      </select></td>
  </tr>
  <!-- next row: first_name1, etc. -->

My idea is that I would store the Player instances that I used in self.shown_players, so that I could later update Players if necessary in my post() method (of the same class) by doing:

def post(self):
    # some code skipped

    for i, player in enumerate(self.shown_players):
        fn = self.request.get('first_name'+str(i)).strip()
        sn = self.request.get('surname'+str(i)).strip()
        gd = self.request.get('gender'+str(i)).strip()
        if any([fn != player.first_name,
                sn != player.surname,
                gd != player.gender]):
            player.first_name = fn
            player.surname = sn
            player.gender = gd
            player.put()

However, this doesn't work because self.shown_players does not exist when the post() method is called. I guess the app engine creates a new instance of the class every time the page is accessed.

I experimented with the same idea but putting shown_players at the class or module level (and calling it global) but this didn't work for reasons that I cannot divine. For example:

shown_players = []
class PlayersPage(webapp.RequestHandler):
    def get(self):
        # Get all the current players, and store the list.
        # We need to store the list so that we can update
        # if necessary in post().
        global shown_players
        shown_players[:] = list(Player.all())

shown_players appears to have the right value within get() because the HTML generates correctly, but it is empty within post().

What should I do?

EDIT: Thanks, all. The answer ("Just retrieve the players again!") should have been obvious :-) Maybe I'll look at memcache one day, but I'm not expecting the player list to get beyond 30 in the near future..

+2  A: 

On each request you are working on a new instance of the same class. That's why you can't create a varable in get() and use its value in post(). What you could do is either retrieve the values again in your post()-method or store the data in the memcache.

Refer to the documentation of memcache here:

http://code.google.com/intl/de-DE/appengine/docs/python/memcache/

Benedikt Eger
+1 for memcached suggestion to reduce hits on the database
Jon Cage
+1  A: 

I've never tried building a google app engine app, but I understand it's somewhat similar to Django in it's handling of databases etc.

I don't think you should be storing things in global variables and instead should be treating each transaction seperately. The get request works because you're doing what you ought to be doing and re-requesting the information from the db.

If you want to update a player in your post function, you probably want to pass in the details, [look up players with those details again], modify them as you please. The bit in brackets is the step you're missing.

Jon Cage
+2  A: 

In your post method, just before the "for" clause, retrieve the players list from where it is stored:

def post(self):
    # some code skipped

    self.shown_players = Player.all().fetch()
    for i, player in enumerate(self.shown_players):
      ...
cjanssen