Python 使用事务更新实体的通用方法

Python 使用事务更新实体的通用方法,python,google-app-engine,Python,Google App Engine,我有一个GAE模型,其中包含几个使用事务更新实体的方法。大概是这样的: class MyModel(ndb.Model): @staticmethod @ndb.transactional def update_foo(ekey): entity = ekey.get() entity.foo = "x" entity.put() @staticmethod @ndb.transactional

我有一个GAE模型,其中包含几个使用事务更新实体的方法。大概是这样的:

class MyModel(ndb.Model):

    @staticmethod
    @ndb.transactional
    def update_foo(ekey):
        entity = ekey.get()
        entity.foo = "x"
        entity.put()

    @staticmethod
    @ndb.transactional
    def update_bar(ekey):
        entity = ekey.get()
        entity.bar = "y"
        entity.put()
class MyModel(ndb.Model):

    @staticmethod
    @ndb.transactional
    def update_tx(ekey, **kwargs):
        entity = ekey.get()
        for prop, value in kwargs.iteritems():
            setattr(entity, prop, value)
        enitty.put()

    def update_foo(self):
        self.update_tx(self.key, foo="x")

    def update_bar(self):
        self.update_tx(self.key, bar="y")
为了清理我的代码,我在想,我可以集中对事务进行更新的代码。大概是这样的:

class MyModel(ndb.Model):

    @staticmethod
    @ndb.transactional
    def update_foo(ekey):
        entity = ekey.get()
        entity.foo = "x"
        entity.put()

    @staticmethod
    @ndb.transactional
    def update_bar(ekey):
        entity = ekey.get()
        entity.bar = "y"
        entity.put()
class MyModel(ndb.Model):

    @staticmethod
    @ndb.transactional
    def update_tx(ekey, **kwargs):
        entity = ekey.get()
        for prop, value in kwargs.iteritems():
            setattr(entity, prop, value)
        enitty.put()

    def update_foo(self):
        self.update_tx(self.key, foo="x")

    def update_bar(self):
        self.update_tx(self.key, bar="y")

这是一个合理的想法,还是这种方法中存在我没有考虑的危险?

这是合理的。这实际上取决于您的用例

实际上,我也有类似的东西,但我越来越需要对每种实体类型的my
update_tx()
进行特殊处理,直到我的~10个模型中只有1或2个仍在使用它,因为几乎总是需要执行其他逻辑

  • 如果我将用户的帐户状态从“停用”更新为“激活”,我需要执行一些查询,以查看他们是否完成了所有必需的入职步骤
  • 如果用户更新了他们的电子邮件,我必须发送一个新的验证链接到新的电子邮件,然后才能更改
  • 仅当实体处于特定状态时,某些字段才可编辑
  • 如果用户提交的是新的开始日期和结束日期,我需要将旧的开始日期和结束日期保存在新对象中,以便于历史记录
这种逻辑可能发生在这个函数之外,但我经常希望它发生在同一个事务中

除此之外,它似乎无法处理的一件事是需要在单个事务中更新一批实体,因此,如果这对您很重要,您的伪代码需要看起来更像这样:

class MyModel(ndb.Model):

    def update_properties(self, **kwargs):
        for prop, value in kwargs.iteritems():
            setattr(self, prop, value)

    @staticmethod
    @ndb.transactional(xg=True)
    def update_txs(keys, updates):
        # keys is an array of ndb.Key()s, 
        # updates is an array of the same size, containing **kwargs for each key
        entities = ndb.get_multi(keys)
        for index, entity in enumerate(entities):
            entity.update_properties(**updates[index])
        ndb.put_multi(entities)

    @classmethod
    def update_tx(cls, ekey, **kwargs):
        cls.update_txs([ekey], [kwargs])

    def update_foo(self):
        self.update_tx(self.key, foo="x")

    def update_bar(self):
        self.update_tx(self.key, bar="y")

嗨,亚历克斯,谢谢你的见解。我正在努力弄清楚交易中需要做什么,以及在交易之前可以做什么。例如,tt似乎可以在事务之前验证表单数据,但其他操作不太清楚。当然可以。您将始终在模型中进行一些验证,事实上,ndb允许您在属性上设置验证器函数。实际上,我正在重构我是如何进行验证的,因为很多规则必须能够被管理员/客户服务代表进行更改(即用户只能在将来设置一个DATE时间,但是管理员需要能够追溯日期)。我目前的做法是在模型/事务中进行数据完整性验证,并基于模型之外的权限进行验证(以及时间戳->日期时间检查)。