I have lots of views manipulating entities of same kind:
def view1(request, key):
user = ndb.Key(urlsafe=key).get()
user.x = 1
user.put()
...
def view2(request, key):
user = ndb.Key(urlsafe=key).get()
user.y = 2
user.put()
...
Obviously, this is error-prone due to possible race conditions (last wins):
- view1 reads whole user entity data (x=None, y=None)
- view2 reads whole user entity data (x=None, y=None)
- view1
user.x = 1
(x=1, y=None) - view2
user.y = 2
(x=None, y=2) - view1
user.put()
(x=1, y=None) - view2
user.put()
(x=None, y=2)
What are best ways to fix this and what behaviour is considered most decent? Transactions (one of the requests is gonna fail, is this ok)?
Wrap your get and put into a transaction. This will ensure you cannot stomp over a different update.
You can read more about transactions with the NDB Client Library documentation.
In your code, you could for example just use the NDB transaction decorator: