В хранилище данных запутались, как передать список ключей в качестве аргумента somemodel.get_or_insert ()? - PullRequest
0 голосов
/ 01 апреля 2010

Есть ли примеры того, как передать список имен ключей в Model.get_or_insert()?

Моя проблема:

С помощью метода ParentLayer я хочу сделать детей.

Key_names новых (или редактируемых) сущностей класса Child будут взяты из следующего списка:

namesList = ["picture1","picture2"]

поэтому я должен иметь возможность построить список имен ключей с помощью метода из родительского класса следующим образом:

class ParentLayer(db.Model):

 def getOrMakeChildren(self, namesList):
            keyslist = [ db.Key.from_path( 'Child' , name , parent = self.key() ) for name in namesList ]

проблема в следующем, где я просто хочу получить сущности get_or_insert на основе keylist, определенного выше:

            childrenEntitiesList = Child.get_or_insert(keyslist) # no works?

также ни одна из следующих попыток не сработала:

            #childrenEntitiesList = Child.get_or_insert(keyslist, parent = u'TEST') 
            #childrenEntitiesList = Child.get_or_insert(keyslist, parent=self.key().name() ) 
            #childrenEntitiesList = Child.get_or_insert(keyslist, parent=self.key() 

1 Ответ

3 голосов
/ 01 апреля 2010

get_or_insert должен использовать транзакцию для атомарного возврата или создания запрошенной сущности, и вы не можете выполнить одну транзакцию для нескольких сущностей. Кроме того, get_or_insert принимает аргументы ключевого слова для конструктора, и нет простого способа указать разные наборы для каждого.

Если вы просто хотите получить get_or_insert несколько ключей, вы можете сделать это:

entities = [Child.get_or_insert(k) for k in keylist]

Как уже упоминалось, для этого потребуется транзакция для каждой сущности. Если вы ожидаете, что рассматриваемые сущности обычно существуют, альтернативная версия get_or_insert может быть более полезной (и эффективной) для вас:

def _get_or_insert_tx(key, properties):
  """When run in a transaction, fetches or creates an entity atomically."""
  entity = db.get(key)
  if not entity:
    entity = db.class_for_kind(key.kind())(key=key, *properties)
    entity.put()
  return entity

def get_or_insert_multiple(args):
  """Fetches or creates multiple entities.

  Args:
    args: A list of (key, dict-of-properties) tuples
  Returns:
    A list of entities, in the same order as args.
  """
  # First, try and fetch them in a batch, outside the transaction
  entities = db.get([x[0] for x in args])
  # Now, transactionally create or fetch each missing one
  for i in range(len(entities)):
    if entities[i] is None:
      entities[i] = db.run_in_transaction(_get_or_insert_tx, *args[i])
  return entities

Этот код сначала попытается выполнить пакетную выборку всех сущностей, которые вы хотите создать, а затем выполнить транзакцию только для сущностей, которые еще не существуют. В лучшем случае он получает одну партию; в худшем случае он выполняет пакетное получение с последующей транзакцией для каждого объекта. Обратите внимание, что, в отличие от встроенного get_or_insert, он использует ключи, а не имена ключей - так как вы использовали синтаксис.

Здесь используется:

entities = get_or_insert_multiple([(k, {}) for k in keys])

Обратите внимание на пустой словарь для каждой сущности, так как вы не указываете какие-либо свойства, которые будут переданы в конструктор для новых сущностей.

...