在Python中复制Google App Engine数据存储中的实体,而不知道“compile”tim处的属性名

2024-04-26 21:34:25 发布

您现在位置:Python中文网/ 问答频道 /正文

在我正在编写的Python Google App Engine应用程序中,我有一个实体存储在数据存储中,需要检索它,对它进行精确复制(除了键),然后将这个实体放回。

我该怎么做?尤其是,我在做这件事的时候,有没有什么需要注意的注意事项或技巧,这样我就可以得到我所期望的那种,而不是别的。

预计到达时间:嗯,我试过了,确实遇到了问题。我希望在编写代码时不必知道属性的名称就可以复制。我的想法是:

#theThing = a particular entity we pull from the datastore with model Thing
copyThing = Thing(user = user)
for thingProperty in theThing.properties():
    copyThing.__setattr__(thingProperty[0], thingProperty[1])

执行时没有任何错误。。。直到我尝试从数据存储中提取copyThing,这时我发现所有属性都设置为None(显然,除了用户和键之外)。很明显,这段代码正在做一些事情,因为它将默认值替换为无(所有属性都有一个默认值集),但完全不是我想要的。建议?


Tags: 数据代码实体app应用程序技巧属性google
3条回答

如果您使用的是NDB,您可以简单地复制: new_entity.populate(**old_entity.to_dict())

这只是Nick Johnson's excellent code的一个扩展,用于解决Amir在注释中突出显示的问题:

  1. ReferenceProperty的db.Key值不再通过不必要的数据存储往返检索。
  2. 现在可以使用auto_now和/或auto_now_add标志指定是否要跳过DateTime属性。

下面是更新的代码:

def clone_entity(e, skip_auto_now=False, skip_auto_now_add=False, **extra_args):
  """Clones an entity, adding or overriding constructor attributes.

  The cloned entity will have exactly the same property values as the original
  entity, except where overridden. By default it will have no parent entity or
  key name, unless supplied.

  Args:
    e: The entity to clone
    skip_auto_now: If True then all DateTimeProperty propertes will be skipped which have the 'auto_now' flag set to True
    skip_auto_now_add: If True then all DateTimeProperty propertes will be skipped which have the 'auto_now_add' flag set to True
    extra_args: Keyword arguments to override from the cloned entity and pass
      to the constructor.
  Returns:
    A cloned, possibly modified, copy of entity e.
  """

  klass = e.__class__
  props = {}
  for k, v in klass.properties().iteritems():
    if not (type(v) == db.DateTimeProperty and ((skip_auto_now and getattr(v, 'auto_now')) or (skip_auto_now_add and getattr(v, 'auto_now_add')))):
      if type(v) == db.ReferenceProperty:
        value = getattr(klass, k).get_value_for_datastore(e)
      else:
        value = v.__get__(e, klass)
      props[k] = value
  props.update(extra_args)
  return klass(**props)

第一个if表达式不是很优雅,因此如果您能分享一个更好的方法来编写它,我将不胜感激。

给你:

def clone_entity(e, **extra_args):
  """Clones an entity, adding or overriding constructor attributes.

  The cloned entity will have exactly the same property values as the original
  entity, except where overridden. By default it will have no parent entity or
  key name, unless supplied.

  Args:
    e: The entity to clone
    extra_args: Keyword arguments to override from the cloned entity and pass
      to the constructor.
  Returns:
    A cloned, possibly modified, copy of entity e.
  """
  klass = e.__class__
  props = dict((k, v.__get__(e, klass)) for k, v in klass.properties().iteritems())
  props.update(extra_args)
  return klass(**props)

示例用法:

b = clone_entity(a)
c = clone_entity(a, key_name='foo')
d = clone_entity(a, parent=a.key().parent())

编辑:使用NDB时的更改

将下面Gus的注释与指定不同数据存储名称的属性的修复结合起来,以下代码适用于NDB:

def clone_entity(e, **extra_args):
  klass = e.__class__
  props = dict((v._code_name, v.__get__(e, klass)) for v in klass._properties.itervalues() if type(v) is not ndb.ComputedProperty)
  props.update(extra_args)
  return klass(**props)

示例用法(注意key_name在NDB中变成id):

b = clone_entity(a, id='new_id_here')

附带说明:请参见使用_code_name来获取Python友好的属性名。否则,像name = ndb.StringProperty('n')这样的属性将导致模型构造函数引发AttributeError: type object 'foo' has no attribute 'n'

相关问题 更多 >