由于唯一性约束在用户名上,因此您必须将其用作数据存储中的键并使用事务。
def txn():
key = ndb.Key(Member, username)
member = key.get()
if member is not None:
raise CustomAlreadyExistsException(member) # This will abort txn
member = Member(
id=username,
Pid=self.request.get('Pid'),
email=self.request.get('email'),
...)
member.put()
ndb.transaction(txn)
这确保只有一个人可以注册用户名。
jQuery 助手会检查是否ndb.Key(Member, userid).get()
给出结果。GET 不是事务性的。
为了提高可用性客户端在检查可用性后“保留”用户名,您可以按照 Daniel 的建议使用 memcached,但我会调用 YAGNI,跳过复杂性,而是让某些人在提交表单后得到验证错误。请注意,memcached 是尽力而为,并且不能保证任何事情。
如果您需要保证多个字段的唯一性,则必须为它们添加模型类并签入跨组 (XG) 事务。
class Pid(ndb.Model):
member = ndb.KeyProperty()
class Email(ndb.Model):
member = ndb.KeyProperty()
class Member(ndb.Model):
pid = ndb.KeyProperty()
email = ndb.KeyProperty()
@property
def pid_value(self):
return self.pid.id()
@property
def email_value(self):
return self.email.id()
def txn():
member_key = ndb.Key(Member, username)
pid_key = ndb.Key(PersonalId, self.request.get('Pid'))
email_key = ndb.Key(Email, self.request.get('email'))
member, pid, email = ndb.get_multi([member_key, pid_key, email_key])
if member is not None or pid is not None or email is not None:
raise CustomAlreadyExistsException(member, pid, email) # This will abort txn
# Create instances referencing each other
email = Email(key=email_key, member=member_key)
pid = Pid(key=pid_key, member=member_key)
member = Member(
key=member_key,
pid=pid_key,
email=email_key,
...)
ndb.put_multi([member, pid, email])
ndb.transaction(txn, xg=True)