3

在任何情况下,GAE 数据存储可能会将属性类型从更改StringPropertyTextProperty(实际上忽略模型定义)?

考虑以下情况(简化):

class MyModel(db.Model):
    user_input = db.StringProperty(default='', multiline=True)

我的数据存储区中此模型的某些实体实例的数据类型为TextPropertyfor 'user_input' (而不是 simple str),因此未编入索引。我可以通过检索实体、设置model_instance.user_input = str(model_instance.user_input)然后将实体放回数据存储区来解决此问题。

我不明白的是,当此模型没有更改时,这仅发生在某些实体上。db.model 的属性的“类型”是否可以从StringPropertyto覆盖TextProperty

4

4 回答 4

1

如果属性没有被索引,至少ndb有一个包含 Unicode 的 StringProperties 的特殊代码路径 。在这种情况下,它变成了一个文本属性:相关的片段是:

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=False)如果您可能将混合值unicodestr值写入属性 - 因为它往往会发生在外部数据中。

于 2018-12-13T14:35:43.917 回答
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!
于 2013-03-07T11:16:45.993 回答
0

长度限制StringProperty为 500 个字符。我不确定,但如果超过限制,数据存储区可能会将 a 转换StringProperty为 a 。TextProperty

话虽如此,我怀疑 GAE 是否会隐式地将索引属性更改为非索引属性。但这是我能想到的。

于 2013-03-06T18:13:13.633 回答
0

通过使用 setattr setattr(some_instance, 'string_type', some_instance.text_type),您实际上已经使名为 string_type 属性的实例属性实际上指向 text_type 属性。所以两个名字一个属性

The db, ndb, users, urlfetch, and memcache modules are imported.
> 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)
> print type(some_instance.string_type)
<class 'google.appengine.api.datastore_types.Text'>
y> repr(some_instance.string_type)
"u'foobar'"
> id(some_instance.string_type)
168217452
> id(some_instance.text_type)
168217452
> some_instance.string_type.__class__
<class 'google.appengine.api.datastore_types.Text'>
> some_instance.text_type.__class__
<class 'google.appengine.api.datastore_types.Text'>
> dir(some_instance.text_type.__class__)

注意上面两个属性的id。

因此,您有效地重新绑定了实例级属性定义,然后将此修改后的模型与字段的类型一起写入数据存储区。

如果你想使用 setattr (虽然在这个人为的例子中看不到为什么)你应该首先从属性setattr(some_instance.string_type,TestModel.string_type.get_value_for_datastore(some_instance) )中获取值来获取要分配的值,而不是重新绑定实例属性。

于 2013-03-08T00:00:10.803 回答