Cross talk on database models because of decorator implementation
我有一个运行应用程序引擎的Web服务器,它使用
数据模型如下所示:
1 2 3 4 | @acl class MyModel(ndb.Model): ... access_control = ndb.JsonProperty(default={}) |
我使用
1 2 3 4 5 6 7 8 | def acl(model): def grant(self, subject, credentials): logging.debug("ACL before: {}".format(self.access_control)) self.access_control[subject] = { ... } # Set correct value. logging.debug("ACL after: {}".format(self.access_control)) model.grant = grant ... ... |
从我的应用程序中,我希望这样称呼它:
1 2 3 4 | >>> mdl = MyModel(...) >>> mdl.grant("someone","creds") ACL before: {} ACL after: { < properly populated access_control > } |
但是我得到了类似的东西:
1 2 3 4 5 6 7 8 9 | >>> mdl1 = MyModel(...) >>> mdl1.grant("someone","creds") ACL before: {} ACL after: { < properly populated access_control > } >>> mdl2 = MyModel(...) >>> mdl2.grant("someone else","other creds") ACL before: { < values from mdl1 > } ACL after: { < values from mdl1 concatenated with mdl2 > } |
这个错误使我怀疑
问题是:为什么我的模型会在它们之间泄漏数据?
模型属性是静态元素。另请参见在Python中定义类变量的正确方法。
类修饰器的存在可能会干扰它们在ndb内部的正常操作,而ndb内部通常会处理属性值的正确初始化。
我对类装饰器还不够熟悉,所以我不确定您是否可以/如何用一个修改过的装饰器来解决这个问题。可能是这样(显式初始化属性)?
1 2 3 4 5 6 7 | def acl(model): def grant(self, subject, credentials): self.access_control = {} # Always start with the default value logging.debug("ACL before: {}".format(self.access_control)) self.access_control[subject] = { ... } # Set correct value. logging.debug("ACL after: {}".format(self.access_control)) model.grant = grant |
我选择实现类似功能的(imho更容易理解)解决方案是使用纯类继承而不是修饰器(但请注意,值的重置相同):
1 2 3 4 5 6 7 8 9 10 | class ACLModel(ndb.Model): access_control = ndb.JsonProperty(default={}) def grant(self, subject, credentials): self.access_control = {} self.access_control[subject] = { ... } # Set correct value. class MyModel(ACLModel): ... # other specific properties |
继承方法允许我对多个模型轻松地使用相同的访问控制代码(自包含)。decorator方法会对使用它的模型提出额外的要求——它们都需要一个