Избранное | Русский | Войти

Создание, получение и удаление данных

API хранилища данных представляет объекты как экземпляры классов моделей. Методы экземпляра модели позволяют создавать, обновлять и удалять объекты. Объекты извлекаются из хранилища данных как экземпляры модели с помощью запросов или ключей.

Создание и обновление объекта

Экземпляры классов ModelExpando) представляют собой объекты хранилища данных. Приложение создает новый объект выбранного типа посредством вызова конструктора класса модели, соответствующего данному типу.

pet = Pet(name="Fluffy",
          type="cat",
          owner=users.get_current_user())

Новый объект не создается в хранилище данных до первого размещения экземпляра путем вызова метода put() экземпляра или передачи экземпляра в функцию db.put().

pet.put()

db.put(pet)

Если экземпляр уже сохранен, метод put() обновляет существующий объект.

Запросы возвращают результаты в виде экземпляров модели. Эти экземпляры можно изменить и вернуть в хранилище данных.

if users.get_current_user():
  user_pets = db.GqlQuery("SELECT * FROM Pet WHERE owner = :1",
                          users.get_current_user())
  for pet in user_pets:
    pet.spayed_or_neutered = True

  db.put(user_pets)

Получение объектов с помощью запроса

Поиск по запросу в хранилище данных выполняется среди объектов заданного типа. Результаты запроса можно фильтровать с помощью условий, которым должны удовлетворять значения свойств объекта, а затем возвращать результаты, отсортированные по значениям свойств. Кроме того, с помощью запроса можно ограничить набор объектов, указав их предка; см. статью Ключи и группы объектов.

Полное описание работы запросов, в том числе действий, которые нельзя выполнить с их помощью, можно найти в статье Запросы и индексы.

API хранилища данных предоставляет два интерфейса для выполнения запросов свойств объекта: Query – интерфейс, который подготавливает запросы с помощью методов объекта запроса, и GqlQuery – интерфейс, использующий язык запросов, подобный SQL и называемый GQL.

Интерфейс Query

Метод all() класса Model (или Expando) возвращает объект Query, который представляет собой запрос всех объектов соответствующего типа. Приложение подготавливает запрос, вызывая методы filter(), order() и ancestor() объекта.

class Story(db.Model):
  title = db.StringProperty()
  date = db.DateTimeProperty()

query = Story.all()

query.filter('title =', 'Foo')
query.order('-date')
query.ancestor(key)

# These methods can be chained together on one line.
query.filter('title =', 'Foo').order('-date').ancestor(key)

Интерфейс GqlQuery

В конструктор класса GqlQuery передается строка запроса GQL и дополнительно связи параметров. В строке запроса указываются тип, фильтры, порядок сортировки и предок. Строка запроса может также содержать сдвиг и ограничение результатов.

# Parameters can be bound with positional arguments.
query = db.GqlQuery("SELECT * FROM Story WHERE title = :1 "
                    "AND ANCESTOR IS :2 "
                    "ORDER BY date DESC",
                    'Foo', key)

# Or, parameters can be bound with keyword arguments.
query = db.GqlQuery("SELECT * FROM Story WHERE title = :title "
                    "AND ANCESTOR IS :parent "
                    "ORDER BY date DESC",
                    title='Foo', parent=key)

# String, number and Boolean values can be literal values in the string.
query = db.GqlQuery("SELECT * FROM Story WHERE title = 'Foo' "
                    "AND ANCESTOR IS :parent "
                    "ORDER BY date DESC",
                    parent=key)

Метод класса gql() класса Model также создает объект GqlQuery из строки. Эта строка аналогична строке запроса GQL за исключением части SELECT * FROM Model, так как она подразумевается.

query = Story.gql("WHERE title = :title "
                  "AND ANCESTOR IS :parent "
                  "ORDER BY date DESC",
                  title='Foo', parent=key)

Можно переопределить связи параметров и связать параметры с новыми значениями с помощью метода bind(). Приложение может повторно использовать объект GqlQuery путем переопределения связей параметров и повторного выполнения запроса.

Выполнение запроса и получение результатов

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

В метод fetch() передается максимальное количество получаемых данных (ограничение) и дополнительно количество результатов, которые следует пропустить (сдвиг). Метод выполняет запрос и извлекает результаты до тех пор, пока их количество не достигнет ограничения либо пока они не будут исчерпаны. После загрузки результатов в память он пропускает количество результатов, равное сдвигу, если таковой указан, и возвращает запрошенные результаты в виде списка экземпляров модели. При каждом вызове метода fetch() выполняется полный запрос.

Примечание. Сдвиг не влияет на количество результатов, извлекаемых из хранилища данных. Извлекаются и хранятся в памяти все результаты, количество которых не превышает заданное ограничение. Сдвиг влияет только на результаты, возвращаемые методом fetch().

results = query.fetch(10)
for result in results:
  print "Title: " + result.title

Ограничение и сдвиг, указанные в методе fetch(), имеют приоритет над соответствующими значениями в строке GQL-запроса.

Если объект запроса используется в качестве итератора, запрос выполняется без ограничения и сдвига, результаты загружаются в память, а затем возвращается результат итерации. Итератор возвращает экземпляры класса модели.

for result in query:
  print "Title: " + result.title

Примечание. В ответ на запрос хранилище данных возвращает не более 1000 результатов, вне зависимости от ограничения и сдвига извлекаемых результатов. Эти 1000 результатов включают все пропущенные посредством сдвига результаты, поэтому запрос с количеством результатов, превышающим 1000, использующий сдвиг 100, вернет 900 результатов.

Получение объекта с помощью ключа

Как только объект помещается в хранилище данных, он получает уникальный ключ. Значения ключей представлены в API как экземпляры класса Key. Метод put() экземпляра модели и функция db.put() возвращают значение Key сохраненного объекта. После первого сохранения экземпляра модели его метод key() возвращает значение Key экземпляра.

entity.put()
key = entity.key()

# ...

entity = db.get(key)

Значение Key в основном используется для хранения экземпляра модели в виде значения свойства другого объекта. Класс свойств модели ReferenceProperty осуществляет автоматическую привязку и разыменование ссылок экземпляров модели как ключей: экземпляр модели можно назначить непосредственно классу ReferenceProperty, а его ключ будет использоваться как значение.

class PetOwner(db.Model):
  name = db.StringProperty()

class Pet(db.Model):
  name = db.StringProperty()
  owner = db.ReferenceProperty(PetOwner)

owner = PetOwner(name="Albert")
pet = Pet(name="Fluffy", owner=owner)

# This is equivalent:
pet = Pet(name="Fluffy", owner=owner.key())

Сходными образом значение ReferenceProperty, к которому осуществляется доступ через свойство, действует как его экземпляр. Объект данных извлекается автоматически при необходимости.

pets = db.GqlQuery("SELECT * FROM Pet WHERE name = :1", "Fluffy")
pet = pets.get()

owner_name = pet.owner.name

Для значений ключей, сохраненных без использования модели ReferenceProperty, таких как динамическое свойство Expando или элемент ListProperty, автоматическое разыменование ссылок не предусмотрено.

Функция db.get() извлекает объект из хранилища данных по значению Key (или списку значений Key).

Для передачи за пределы приложения ключи можно кодировать как строки. Чтобы преобразовать ключ из строки обратно в объект Key, приложение передает строку в конструктор класса Key.

obj = MyModel(name="Foo")
self.response.write('<a href="/view?key=%s">%s</a>' % (str(obj.key()), 
                                                      obj.name()))

# ...

key_name = self.request.get('key')
obj = db.get(db.Key(key_name))

Примечание. Кодировка строки Key непрозрачна, но при этом строка не зашифрована. Если требуется, чтобы ключи в приложении нельзя было угадать, перед отправкой пользователю закодированное в виде строки значение Key следует зашифровать.

Удаление объекта

Приложение может удалить объект из хранилища данных с помощью экземпляра модели или значения Key. Метод delete() экземпляра модели удаляет соответствующий объект из хранилища данных. В функцию delete() передается значение Key или список значений Key, и она удаляет объект или объекты из хранилища данных.

q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
results = q.fetch(10)
for result in results:
  result.delete()

# or...

q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
results = q.fetch(10)
db.delete(results)

При удалении объекта значения Key в хранилище данных, которые могли ссылаться на него, не будут изменены. Если приложение пытается разыменовать ссылку значения Key удаленного объекта, оно должно выполнить это с помощью функции db.get(), а затем проверить возвращенное значение перед обращением к свойствам.

Удаление объекта, являющегося предком других объектов, не повлияет на эти объекты. Так как приложение не учитывает существование предка при создании ключей для экземпляров потомков, оно сможет по-прежнему осуществлять доступ к ним.