db.StringProperty但属性偶尔是datastore_types.Text?

3 投票
4 回答
641 浏览
提问于 2025-04-17 18:09

有没有可能在某些情况下,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 个回答

0

StringProperty中,字符串的长度限制是500个字符。我不太确定,但可能如果超过这个限制,数据存储系统会把StringProperty转换成TextProperty

不过,我觉得谷歌应用引擎(GAE)不会自动把一个有索引的属性变成没有索引的属性。这是我能想到的所有可能性。

1

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()

如果你可能会向这个属性写入混合的unicodestr值,最好避免使用StringProperty(indexed=False),因为这在处理外部数据时很常见。

0

结果发现,有一种方法可以绕过模型定义中属性的类型(这正是我们的情况)!下面这个完整的例子可以在交互式控制台中运行,并展示了这个问题。简单来说,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!

撰写回答