db.StringProperty但属性偶尔是datastore_types.Text?
有没有可能在某些情况下,GAE的数据存储会把一个属性的类型从 StringProperty
改成 TextProperty
,也就是不管模型的定义?
想象一下这样的情况(简化版):
class MyModel(db.Model):
user_input = db.StringProperty(default='', multiline=True)
在我的数据存储中,这个模型的一些实体实例的 'user_input' 属性的类型是 TextProperty
(而不是简单的 str
),所以它们没有被索引。我可以通过获取这个实体,然后执行 model_instance.user_input = str(model_instance.user_input)
,再把这个实体放回数据存储来解决这个问题。
我不明白的是,为什么只有一些实体会出现这种情况,而这个模型并没有发生任何变化。难道数据库模型的属性类型会从 StringProperty
被覆盖成 TextProperty
吗?
4 个回答
在StringProperty
中,字符串的长度限制是500个字符。我不太确定,但可能如果超过这个限制,数据存储系统会把StringProperty
转换成TextProperty
。
不过,我觉得谷歌应用引擎(GAE)不会自动把一个有索引的属性变成没有索引的属性。这是我能想到的所有可能性。
在ndb
中,如果一个字符串属性包含Unicode字符,并且这个属性没有被索引,那么它会被转换成文本属性。相关的代码片段如下:
if isinstance(value, str):
v.set_stringvalue(value)
elif isinstance(value, unicode):
v.set_stringvalue(value.encode('utf8'))
if not self._indexed:
p.set_meaning(entity_pb.Property.TEXT)
我在Python这边没有观察到这个现象(可以参考这个链接:db.StringProperty但属性偶尔是datastore_types.Text?),但是我在数据存储中看到了这个问题,这在把数据存储加载到BigQuery时给我带来了麻烦。
所以建议只使用:
- StringProperty(indexed=True)
- TextProperty()
如果你可能会向这个属性写入混合的unicode
和str
值,最好避免使用StringProperty(indexed=False)
,因为这在处理外部数据时很常见。
结果发现,有一种方法可以绕过模型定义中属性的类型(这正是我们的情况)!下面这个完整的例子可以在交互式控制台中运行,并展示了这个问题。简单来说,setattr
可以绕过属性的类型,如果你给一个已有的属性赋值为不同类型的值:
from google.appengine.ext import db
class TestModel(db.Model):
string_type = db.StringProperty(default='', multiline=True)
text_type = db.TextProperty()
some_instance = TestModel()
some_instance.text_type = 'foobar'
setattr(some_instance, 'string_type', some_instance.text_type)
some_instance.put()
retrieved_instance = db.get(some_instance.key())
print id(retrieved_instance.string_type) #10166414447674124776
print id(retrieved_instance.text_type) #10166414447721032360
print type(retrieved_instance.string_type) #OOPS: string_type is now Text type!