使用GAE数据库进行强一致性查询以进行寄存器验证

时间:2012-12-15 21:44:24

标签: python google-app-engine consistency ancestor

我正在尝试为用户创建一个简单的注册表。为了使该寄存器保持一致,我不能允许使用相同的用户名注册两个用户,这是因为默认查询的最终一致性。我知道即使流量很大,发生这种情况的几率几乎为0,我希望我的实施能够稳固。我已经实现了应该是非常一致的祖先查询,但是当我发布我的应用程序并测试它时,如果我正确的时间,我可以使用相同的用户名注册2个用户。

def user_parent(group = 'default'):
key = ndb.Key('users', group)
return key

class User(ndb.Model):
    username = ndb.StringProperty(required = True)
    email = ndb.StringProperty(required = True)
    password = ndb.StringProperty(required = True)

@classmethod
def register(cls, username, password, email):
    return User(parent = user_parent(),
                username = username,
                password = password,
                email = email)

@classmethod
def by_name(cls, name):
    return User.query(User.username == name, ancestor = user_parent()).get()

@classmethod
def by_id(cls, uid):
    return User.get_by_id(uid, parent = user_parent()) 

@classmethod
def by_email(cls, email):
    logging.error(User.query(User.email == email, ancestor = user_parent()).get())
    return User.query(User.email == email, ancestor = user_parent()).get()

@classmethod
def login(cls, user, password):
    u = cls.by_name(user)
    if u and u.password == password:
        return u

我使用reg_submit来执行ajax请求,我对编程很新,并且怀疑这是解决它的最佳解决方案,但我的想法是在这里我使用对User模型类的调用进行验证。

    if reg_submit == 'True':
        reg_email = self.request.get('reg_email')
        reg_user = self.request.get('reg_user')
        reg_password = self.request.get('reg_password')
        reg_verify = self.request.get('reg_verify')

        valid = True
        if not valid_usr(reg_user):
            valid = False
            self.write('user')
            return
        if not valid_mail(reg_email):
            valid = False
            self.write('mail')
            return

        if User.by_email(reg_email):
            valid = False
            self.write('mail')
            return

        if User.by_name(reg_user):
            valid = False
            self.write('user')
            return

        if not valid_pass(reg_password):
            valid = False

        if reg_password != reg_verify:
            valid = False

        if valid:
            t = User.register(reg_user, reg_password, reg_email)
            t.put()
            self.login(t)
            self.redirect('/')

通过使查询强烈一致,我理解的是,在我的数据库被复制到的每台机器都将被更新之前,所述查询将不会执行。

如何实现强一致性查询,其中两个用户同时使用相同的用户名注册,其中一个用户将无法执行此操作。

2 个答案:

答案 0 :(得分:1)

Model.get_or_insert (key_name, **kwds)
  

尝试使用给定的密钥获取模型类型的实体   名称。如果存在,get_or_insert()只返回它。如果没有   存在,一个在kwds中具有给定种类,名称和参数的新实体   创建,存储和返回。

     

get和后续(可能)put操作包含在a中   事务确保原子性。这意味着get_or_insert()会   永远不会覆盖现有实体,并且会插入新实体   并且只有当没有具有给定种类和名称的实体时才存在。

Get Or Insert

将用户名用作key_name。设置您的模型,使其具有默认值,例如“new = True”,并检查当您返回模型时,查看它是刚刚创建的还是已经存在,当您要求它时。配置模型并将其保存回来时,请设置“new = False”。

答案 1 :(得分:1)

您需要在事务中运行check-query和put。使用NDB执行此操作的文档为here