2
votes

This is really a python language question, but its wrapped around a Google appengine specific problem.

We have

class User( db.Model ) :
  email = db.StringProperty()
  name = db.StringProperty()
  password = db.StringProperty()
  # more fields..

Because the user account is accessed so often, we keep a copy in session using gaeutilities (as a bonus question, is this bad on GAE? I thought I'd relieve the db a bit.)

class UpdateProfile( webapp.RequestHandler ):
  def post( self ):
    # User posting update to his name
    self.session = sessions.Session()

    #######
    # way#1: update the copy of the User object in SESSION, then .put() it
    self.session[ 'current_user' ].name = self.request.get( 'name' )
    self.session[ 'current_user' ].put()
    # does not work.
    #######

    #######
    # way#2: make a copy of the User object in SESSION, then .put() it
    user = self.session[ 'current_user' ]
    user.name = self.request.get( 'name' )
    user.put()
    # works to update the datastore, but the copy of user in self.session
    # is NOT UPDATED!  I thought Python was
    # pass-by-reference.  It is when you work with lists anyway.
    # Why isn't it "acting right" with this type of object??
    #######


    #######
    # way#3: way that works.
    user = self.session[ 'current_user' ]
    user.name = self.request.get( 'name' )
    user.put()
    self.session[ 'current_user' ] = user
    # works completely
    #######

What is happening in each of these 3 cases? Why don't cases 1 and 2 work?

3

3 Answers

1
votes

Sorry, I'm new to this site, and I don't see where to comment on an answer?

Anyway, I've fixed the specific issue that instigated the original post. While serialization of data is still suboptimal, happening on write, I have managed to make sure assigning model entities as items in a session will work as expected. Rather than get into rewriting the serialization (would be a major rewrite), I instead chose to detect when a model was being inserted as a session data item, and set a ReferenceProperty for it. This means that the model objects never have to get the overhead of being serialized at all.

If the entity the ReferenceProperty is associated is deleted, the ReferenceProperty in the session will be deleted when you try to load it as well. This does mean you'll have to catch exceptions such as KeyError that are raised by Session, as a dictionary should. I hope this is intuitive enough, but am open to any comments. I'll check this page again a few times over the next several weeks.

3
votes

I'm guessing:

Putting objects in the Session means that the objects is serialized ( pickled usually ) and stored somewhere (disk, memory, db). When it is retrieved from the Session, a new object is created from serialized the old state.

  • In the first example each self.session[ 'current_user' ] gives you a new object, one of which you update and the other is saved to the db.
  • In the 2nd you get one object, save it to the DB but not in the session.

Btw, Python does "call by sharing", but that has nothing to do with your problem ;-)

2
votes

I'm the author of gaeutilities. I contacted Nick to talk about this, and he gave me some good ideas. I'll have a solution for this in the final 1.3 release.