This problem is solved already in webapp2 micro framework. Take a look on this docs and on this blog post as well. Copy-pasted code with basic sample:
from google.appengine.ext.ndb import model
class Unique(model.Model):
@classmethod
def create_multi(cls, values):
keys = [model.Key(cls, value) for value in values]
entities = [cls(key=key) for key in keys]
func = lambda e: e.put() if not e.key.get() else None
created = [model.transaction(lambda: func(e)) for e in entities]
if created != keys:
# A poor man's "rollback": delete all recently created records.
model.delete_multi(k for k in created if k)
return False, [k.id() for k in keys if k not in created]
return True, []
@classmethod
def delete_multi(cls, values):
return model.delete_multi(model.Key(cls, v) for v in values)
# Assemble the unique values for a given class and attribute scope.
uniques = [
'User.username.%s' % username,
'User.auth_id.%s' % auth_id,
'User.email.%s' % email,
]
# Create the unique username, auth_id and email.
success, existing = Unique.create_multi(uniques)
if success:
# The unique values were created, so we can save the user.
user = User(username=username, auth_id=auth_id, email=email)
user.put()
return user
else:
# At least one of the values is not unique.
# Make a list of the property names that failed.
props = [name.split('.', 2)[1] for name in uniques]
raise ValueError('Properties %r are not unique.' % props)