views:

43

answers:

2

I came across this syntax browsing through code for examples. From its surrounding code, it looked like would a) get the entity with the given keyname or b) if the entity did not exist, create a new entity that could be saved. Assume my model class is called MyModel.

my_model = MyModel(key_name='mymodelkeyname', 
                   kwarg1='first arg', kwarg2='second arg')

I'm now running into issues, but only in certain situations. Is my assumption about what this snippet does correct? Or should I always do the following?

my_model = MyModel.get_by_key_name('mymodelkeyname')
if not my_model:
    my_model = MyModel(key_name='mymodelkeyname', 
                       kwarg1='first arg', kwarg2='second arg')
else:
    # do something with my_model
+1  A: 

Is this what you are looking for -> http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_get_or_insert

Ilian Iliev
+2  A: 

The constructor, which is what you're using, always constructs a new entity. When you store it, it overwrites any other entity with the same key.

The alternate code you propose also has an issue: it's susceptible to race conditions. Two instances of that code running simultaneously could both determine that the entity does not exist, and each create it, resulting in one overwriting the work of the other.

What you want is the Model.get_or_insert method, which is syntactic sugar for this:

def get_or_insert(cls, key_name, **kwargs):
  def _tx():
    model = cls.get_by_key_name(key_name)
    if not model:
      model = cls(key_name=key_name, **kwargs)
      model.put()
    return model
  return db.run_in_transaction(_tx)

Because the get operation and the conditional insert take place in a transaction, the race condition is not possible.

Nick Johnson