Индивидуальное моделирование NDB с помощью KeyProperty

Я новичок в ndb, но я уже понял, что мне нужно перепрограммировать определенную область в моем мозгу для создания моделей. Я пытаюсь создать простую модель - просто для понимания того, как спроектировать базу данных ndb - с отношением один к одному: например, пользователь и его информация. После долгих поисков - нашел документацию, но было трудно найти разные примеры - и немного поэкспериментировал (моделирование и запросы несколькими разными способами), это решение, которое я нашел:

from google.appengine.ext import ndb

class Monster(ndb.Model):
    name = ndb.StringProperty()

    @classmethod
    def get_by_name(cls, name):
        return cls.query(cls.name == name).get()

    def get_info(self):
        return Info.query(Info.monster == self.key).get()

class Info(ndb.Model):
    monster = ndb.KeyProperty(kind='Monster')
    address = ndb.StringProperty()

a = Monster(name = "Dracula")
a.put()

b = Info(monster = a.key, address = "Transilvania")
b.put()

print Monster.get_by_name("Dracula").get_info().address

NDB не принимает соединения, поэтому нужно эмулировать желаемое "соединение" с использованием методов и свойств класса. С помощью описанной выше системы я могу легко получить доступ к свойству во второй базе данных (Info) через уникальное свойство в первой (в данном случае «имя» — предположим, что нет двух монстров с одинаковым именем).

Однако, если я хочу напечатать список со 100 именами монстров и соответствующими адресами, вторая база данных (информация) будет поражена 100 раз.

Вопрос: есть ли лучший способ смоделировать это для повышения производительности?


person Richard Haber    schedule 20.04.2013    source источник


Ответы (2)


Если это действительно отношения один к одному, зачем создавать 2 модели. Учитывая ваш пример, объект Address не может быть передан ни одному монстру, так почему бы не поместить данные адреса в монстра.

Есть несколько причин, по которым вы бы этого не сделали.

  1. Адрес может стать большим и, следовательно, менее эффективным для получения сотен свойств, когда вам нужна только пара, хотя в этом могут помочь запросы проекта.

  2. Вы передумали и хотите увидеть всех монстров, которые живут в Трансильвании — в этом случае вы должны создать адресную сущность, а у монстра будет ключевое свойство, указывающее на адрес. Это, очевидно, терпит неудачу, когда вы понимаете, что некоторые монстры могут жить в нескольких местах (оборотни — Лондон, Трансильвания, Нью-Йорк ;-), и в этом случае у вас либо есть повторяющееся свойство KeyProperty в монстре, либо промежуточный объект, который указывает на монстра и адрес. В вашем случае я не думаю, что у монстров в целом так много задокументированных адресов ;-)

Кроме того, если вы однозначно идентифицируете монстров по имени, вам следует подумать о сохранении имени как части ключа. Выполнение Monster.get_by_id("dracula") выполняется быстрее, чем запрос по имени.

Как я написал (плохо) в комментарии. Если 1. выше выполняется, и это истинное отношение один к одному. Затем я бы создал Address как дочернюю сущность (Monster является родителем/предком в ключе) при создании адреса. Это позволяет вам,

  1. разрешить другим объектам указывать на адрес,
  2. Если вы создаете кучу дочерних сущностей, извлекайте их с помощью одного запроса предка). 3 Если вы получили монстра, и он снова принадлежит объектам, это запрос предка.
  3. Если у вас есть куча сущностей, которые должны существовать только в том случае, если существует экземпляр Monster, и они не являются дочерними, тогда вам нужно выполнять запросы ко всем типам сущностей с KeyProperty, совпадающим с ключом, и если эти сущности не являются полимоделями, тогда вам нужно выполнить запрос для каждого типа объекта (и знать, что вам нужно выполнить запрос для данного объекта, который включает в себя реестр определенного типа или жесткое программирование)
person Tim Hoffman    schedule 20.04.2013
comment
'@Tim' спасибо за ответ. Причина 1 правильная. Информация станет большой, я добавлю много других свойств, таких как город монстра, страна, номер телефона и т. д., и они мне не нужны каждый раз, когда я запрашиваю монстра. И я свяжу с ними другие модели с такой информацией, как last_appearance, eat_people (логическое значение). Я не сохраняю имя как часть ключа, потому что хочу иметь возможность его изменить (например, имя пользователя на некоторых веб-сайтах). Однако я также могу просто добавить правило, согласно которому свойство «имя» не может быть изменено и должно быть уникальным. - person Richard Haber; 20.04.2013
comment
хорошо, учитывая это, я бы сделал адрес дочерним объектом (укажите, что монстр является родителем при построении, возможно, с известным именем ключа). Он знает, что бизнес существует без монстра, другие сущности могут ссылаться на него напрямую. Это может быть целая куча дочерних сущностей, которые затем можно получить с помощью одного запроса предка. - person Tim Hoffman; 21.04.2013
comment
Хорошо, Тим, отлично! Поскольку я новичок в ndb, а в документации не хватает практических примеров, не могли бы вы показать мне код? Я играл с дочерними/родительскими отношениями в интерактивной консоли, но ничего не понял, я не очень хорошо понимаю, как это работает. Спасибо! - person Richard Haber; 21.04.2013

Я подозреваю, что то, что вы, возможно, пытаетесь достичь, может быть достигнуто с помощью элементов, описанных в приведенной ниже ссылке. Посмотрите «Операции с несколькими ключами или объектами», «Модели Expando», «Модельные хуки».

https://developers.google.com/appengine/docs/python/ndb/entities

(Вероятно, это больше комментарий, чем ответ)

person Community    schedule 20.04.2013
comment
Итак, у меня есть отношение один к одному, и я хочу получить список со свойствами из обеих моделей. Какой шаблон будет лучшим для этого? Есть много способов сделать это, Тим (выше) уже сказал, что использование ID для извлечения объекта быстрее, чем запрос. Видите ли, мне не хватает документации ndb с общими шаблонами. - person Richard Haber; 20.04.2013