How can I create a new model entity, and then read it immediately after?
Asked Answered
R

1

5

My question is, what is the best way to create a new model entity, and then read it immediately after. For example,

class LeftModel(ndb.Model):
    name = ndb.StringProperty(default = "John")
    date = ndb.DateTimeProperty(auto_now_add=True)

class RightModel(ndb.Model):
    left_model = ndb.KeyProperty(kind=LeftModel)
    interesting_fact = ndb.StringProperty(default = "Nothing")

def do_this(self):
    # Create a new model entity
    new_left = LeftModel()
    new_left.name = "George"
    new_left.put()

    # Retrieve the entity just created
    current_left = LeftModel.query().filter(LeftModel.name == "George").get()

    # Create a new entity which references the entity just created and retrieved
    new_right = RightModel()
    new_right.left_model = current_left.key
    new_right.interesting_fact = "Something"
    new_right.put()

This quite often throws an exception like:

AttributeError: 'NoneType' object has no attribute 'key'

I.e. the retrieval of the new LeftModel entity was unsuccessful. I've faced this problem a few times with appengine and my solution has always been a little hacky. Usually I just put everything in a try except or a while loop until the entity is successfully retrieved. How can I ensure that the model entity is always retrieved without running the risks of infinite loops (in the case of the while loop) or messing up my code (in the case of the try except statements)?

Roslynrosmarin answered 21/7, 2012 at 9:21 Comment(1)
just set a key for LeftModel upon creation instead of using the automatically generated one.Stockish
E
9

Why are you trying to fetch the object via a query immediately after you have performed the put().

You should use the new_left you just created and immediately assign it to the new_right as in new_right.left_model = current_left.key

The reason you can not query immediately is because HRD uses an eventual consistency model, which means you result of the put will be visible eventualy. If you want a consistent result then you must perform ancestor queries and this implies an ancestor in the key on creation. Given you are creating a tree this is probably not practical. Have a read about Structuring Data for Strong Consistency https://developers.google.com/appengine/docs/python/datastore/structuring_for_strong_consistency

I don't see any reason why you just don't use the entity you just created without the additional query.

Elka answered 21/7, 2012 at 11:56 Comment(2)
+1 To amplify: "how do I read it immediately after?" you can't, that's not a design goal of NDB and there is good reason that it isn't available immediately.Foxy
To clarify: that reason has nothing to do with NDB -- these HRD query semantics are implemented in the backend. NDB just passes along the bad news. (As to why the OP is attempting this: my guesses are as good as any, but I'd expect the example is simplified compared to the real code where this happened, and/or they are writing some kind of test; also they perhaps were translating SQL idioms to App Engine.)Margartmargate

© 2022 - 2024 — McMap. All rights reserved.