在Google App Engine中,我将引用的属性列表大致如下:
class Referenced(BaseModel):
name = db.StringProperty()
class Thing(BaseModel):
foo_keys = db.ListProperty(db.Key)
def __getattr__(self, attrname):
if attrname == 'foos':
return Referenced.get(self.foo_keys)
else:
return BaseModel.__getattr__(self, attrname)
这样,有人可以拥有Thing
并说出thing.foos
并从中获取合法的内容。当有人说thing.foos.append(x)
时会出现问题。这不会保存添加的属性,因为基础的键列表保持不变。所以我很快写了这个解决方案,以便将密钥附加到列表中:
class KeyBackedList(list):
def __init__(self, key_class, key_list):
list.__init__(self, key_class.get(key_list))
self.key_class = key_class
self.key_list = key_list
def append(self, value):
self.key_list.append(value.key())
list.append(self, value)
class Thing(BaseModel):
foo_keys = db.ListProperty(db.Key)
def __getattr__(self, attrname):
if attrname == 'foos':
return KeyBackedList(Thing, self.foo_keys)
else:
return BaseModel.__getattr__(self, attrname)
这非常适用于概念验证,因为它在调用append
时完全按预期工作。但是,我绝不会将此内容提供给其他人,因为他们可能会以其他方式(thing[1:9] = whatevs
或thing.sort()
)改变列表。当然,我可以定义所有的__setslice__
和诸如此类的东西,但这似乎让我对于讨厌的错误开放。但是,这是我能想到的最好的解决方案。
有没有更好的方法来做我想做的事情(或许在Python库中)?或者我是以错误的方式解决这个问题并试图让事情过于顺利?
答案 0 :(得分:2)
如果你想修改这样的东西,你不应该改变模型上的__getattr__
;相反,你应该写一个custom Property class。
正如您所观察到的那样,创建一个可行的“ReferenceListProperty”很困难且涉及很多,并且存在许多微妙的边缘情况。我建议坚持使用密钥列表,并在需要时在代码中获取引用的实体。