Google app engine 对于ndb.JsonProperty,值从一个实例泄漏到另一个实例

Google app engine 对于ndb.JsonProperty,值从一个实例泄漏到另一个实例,google-app-engine,app-engine-ndb,google-app-engine-python,Google App Engine,App Engine Ndb,Google App Engine Python,所以,我把我讨厌的问题缩小到这个 class TestModel(ndb.Model): json1 = ndb.JsonProperty(default={}) entity1 = TestModel() entity1.json1['val1'] = 'added via entity1' entity2 = TestModel() entity2.json1['val2'] = 'added via entity2' logging.warn('entity2.json1 =

所以,我把我讨厌的问题缩小到这个

class TestModel(ndb.Model):
    json1 = ndb.JsonProperty(default={})

entity1 = TestModel()
entity1.json1['val1'] = 'added via entity1'

entity2 = TestModel()
entity2.json1['val2'] = 'added via entity2'
logging.warn('entity2.json1 = {}'.format(entity2.json1))
在日志中,我看到以下内容:

... entity2.json1 = {'val2': 'added via entity2', 'val1': 'added via entity1'}
令人惊讶且极其危险的是,我看到在第一个实例中设置的一个值,
entity1
,已经泄漏到第二个实例中,
entity2

我期望
TestModel
的第二次实例化为我提供一个“干净”的实例,特别是因为我对
JsonProperty
default={}
,这是不合理的吗?我应该做一些我没有做的事情吗。或者这可能是ndb的一个bug

更新:到目前为止我最好的解决方法是:始终执行
TestModel(json1={})
。但我想我担心的是,如果我们的一个开发人员忘记这样做,我们可能会让一个客户的数据泄漏到另一个客户


更新:似乎已经有bug报告给谷歌了。表明此(错误)行为可能在请求之间发生。三年前开业,;仍在等待修复。

对于任何对这个问题感兴趣的人,我已经确定了一个解决方法,可以让我晚上睡得更好。这不适合上面的评论,所以我在回答我自己的问题(希望没问题)

这似乎是一个3年前的bug(请参阅),所以很可能不会很快得到修复。上面的解决方法包括始终执行
TestModel(json1={})
或子分类
JsonProperty
,并始终使用我的自定义类,而不是ndb的类(我必须对所有其他类似的属性(如
PickleProperty
)重复)。这些都是可行的,但让我担心的是,项目中的每个开发人员都必须始终在代码库中的任何地方做正确的事情。哈!

因此,这里有一个变通方法,意味着“做正确的事情”只局限于我的模型(不用担心代码)

类测试模型(ndb.Model):
json1=ndb.JsonProperty(默认值={})
定义初始(自我,**kwargs):

setdefault('json1',{})#这是一个鬼鬼祟祟的测试——我只是在编写一些测试时注意到,这些测试碰巧多次实例化了具有类似属性的对象。这不是一个bug,它与任何其他具有可变默认值的函数def相同。dict似乎在请求之间重置自己,不确定这是ndb还是描述符创建的某些方面。我认为唯一的补救办法是提高警惕,或者也许是一个定制的林特规则。谢谢@snakecharmerb,很高兴听到我不是唯一的一个。我是一个长期的GAE用户,直到最近才开始使用它。在过去,我必须一直在JsonProperty中设置相同的值。我没有意识到我是在替换值,而不是添加值。@snakecharmerb,我仔细考虑了您的评论,它类似于函数
def
s中参数的默认值。可能是这样,但不一定是这样。理想情况下,当创建一个新实例时,NDB应该赋值<代码>拷贝.Debug(默认)。这很方便,但我仍然倾向于认为它不是一般情况下的bug。另一方面,我在远程shell中创建了一个带有JsonProperty的模型,并在两个不同的名称空间中使用不同的键进行保存;第二个命名空间中的实体包含第一个命名空间中保存的模型中的键。我认为有一种更强烈(尽管不是100%)的观点认为这是一个bug,因为跨名称空间的数据泄漏破坏了多租户契约。但是,如果谷歌不解决它,我想你将不得不将JsonProperty子类化并自己实现deepcopy:-)基本上,无论你在哪里使用默认参数和可变数据结构,如dict或list(例如,
default={}
),你都会遇到麻烦。不仅仅是ndb。看见
class TestModel(ndb.Model):
    json1 = ndb.JsonProperty(default={})

    def __init__(self, **kwargs):
        kwargs.setdefault('json1', {})     # <---- ADDED THIS!
        super(TestModel, self).__init__(**kwargs)