Отслеживание обратных ссылок неизвестных типов в NDB

Я нахожусь в процессе написания своего первого веб-сервиса RESTful поверх GAE и среды выполнения Python 2.7; Я начал с использования блестящего нового ndb API Гвидо.

Однако я не уверен, как решить конкретный случай без неявной функции обратной ссылки исходного API базы данных. Если пользовательский агент запрашивает определенный ресурс, и эти ресурсы удалены на 1 степень:

хост/апи/вид/идентификатор?глубина=2

Каков наилучший способ обнаружить связанный набор сущностей из "одного" в отношении "один ко многим", учитывая, что тип связанного объекта неизвестен во время разработки?

  • Я не могу использовать запрос на замену, как описано в предыдущий запрос SO из-за последнего ограничения. Тот факт, что мою модель можно определить во время выполнения (и, следовательно, она не жестко запрограммирована), не позволяет мне использовать запрос для фильтрации свойств для сопоставления ключей.

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

До сих пор единственная идея, которая у меня была (помимо возврата к db api), состоит в том, чтобы использовать межгрупповую транзакцию для написания моей собственной ссылки на «один», либо путем обновления ndb.StringProperty(repeat=True), содержащего все связанные типы, когда вводится объект нового типа, или просто поддерживая список ключей в "одном" ndb.KeyProperty(repeat=True) каждый раз, когда связанный "много" объект записывается в хранилище данных.

Я надеюсь, что кто-то более опытный, чем я, может предложить лучший подход.

Учитывая предложение jmort253, я попытаюсь дополнить свой вопрос конкретным примером, адаптированным из документов:

class Contact(ndb.Expando):
    """ The One """

    # basic info
    name = ndb.StringProperty()
    birth_day = ndb.DateProperty()

    # If I were using db, a collection called 'phone_numbers' would be implicitly 
    # created here.  I could use this property to retrieve related phone numbers 
    # when this entity was queried.  Since NDB lacks this feature, the service 
    # will neither have a reference to query nor the means to know the 
    # relationship exists in the first place since it cannot be hard-coded.  The
    # data model is extensible and user-defined at runtime; most relationships
    # will be described only in the data, and must be discoverable by the server.
    # In this case, when Contact is queried, I need a way to retrieve the
    # collection of phone numbers.

    # Company info.
    company_title = ndb.StringProperty()
    company_name = ndb.StringProperty()
    company_description = ndb.StringProperty()
    company_address = ndb.PostalAddressProperty()

class PhoneNumber(ndb.Expando):
    """ The Many """

    # no collection_name='phone_numbers' equivalent exists for the key property
    contact = ndb.KeyProperty(kind='Contact')
    number = ndb.PhoneNumberProperty()

person yo22arian    schedule 24.05.2012    source источник
comment
Привет, не могли бы вы показать пример, чтобы помочь понять проблему немного лучше. Многие люди визуалы, поэтому зрение может помочь прояснить ваш вопрос. Удачи! :)   -  person jmort253    schedule 24.05.2012
comment
Если вы не знаете, какую сущность вы ищете, что вы собираетесь делать с ней/ними, когда найдете их?   -  person Nick Johnson    schedule 25.05.2012
comment
Сервисный уровень просто сериализует обнаруженные им связанные объекты в JSON-представление явно запрошенного объекта. Клиентское приложение должно определить, как они используются; серверу все равно.   -  person yo22arian    schedule 25.05.2012


Ответы (2)


Интересный вопрос! Таким образом, в основном вы хотите посмотреть на класс Contact и выяснить, есть ли какой-либо другой класс модели, который имеет KeyProperty, ссылающийся на него; в этом примере PhoneNumber (но их может быть много).

Я думаю, что решение состоит в том, чтобы попросить ваших пользователей явно добавить эту ссылку при создании класса PhoneNumber.

Вы можете упростить это для своих пользователей, предоставив им подкласс KeyProperty, который позаботится об этом; например

class LinkedKeyProperty(ndb.KeyProperty):
    def _fix_up(self, cls, code_name):
        super(LinkedKeyProperty, self)._fix_up(cls, code_name)
        modelclass = ndb.Model._kind_map[self._kind]
        collection_name = '%s_ref_%s_to_%s' % (cls.__name__,
                                               code_name,
                                               modelclass.__name__)
        setattr(modelclass, collection_name, (cls, self))

Как именно вы выбираете имя для коллекции и значение для хранения, зависит от вас; просто поместите туда что-нибудь, чтобы вам было легко вернуться по ссылке. В примере будет создан новый атрибут для контакта:

Contact.PhoneNumber_ref_contact_to_Contact == (PhoneNumber, PhoneNumber.contact)

[отредактировано, чтобы заставить код работать и добавить пример. :-) ]

person Guido van Rossum    schedule 24.05.2012
comment
Большое спасибо за пост, и еще больше за непрошеную разработку. Б) Ваш синопсис проблемы точен. Это также представляется правильным подходом. Я постепенно начинаю понимать механику, стоящую за этим, когда я просматриваю исходный код пакета; однако self._kind, который соответствует kwarg, переданному конструктору LinkedKeyProperty(kind='Contact'), по какой-то причине не существует на карте вида - по крайней мере, не в моей реализации. В случае примера я предполагаю, что это должна быть ссылка на модель Contact. - person yo22arian; 26.05.2012
comment
Если вы напишите LinkedKeyProperty точно так, как я показал, он должен работать. Возможно, вы не получили его из ndb.KeyProperty? Или вы сначала не сделали вызов super()? Если вы не можете заставить его работать, покажите полный код, который вы пробовали, и полную трассировку. - person Guido van Rossum; 29.05.2012
comment
Это работает отлично. Ошибка явно была моей и возникла из-за какого-то необъяснимого изменения состояния приложения, не имевшего ничего общего с источником. Я пытался воспроизвести эту ошибку несколько раз в поисках лучшего объяснения, но пришел к выводу, что лучше потратить время на то, чтобы новые функции работали, а не объяснять, почему они не работают. - person yo22arian; 29.05.2012

Похоже на хороший пример использования ndb.StructuredProperty.

person proppy    schedule 24.05.2012
comment
Спасибо за предложение! Однако в моем случае у ndb.StructuredProperty есть собственное дисквалифицирующее ограничение: его нельзя получить независимо от объекта Contact, которому [оно] принадлежит. - person yo22arian; 24.05.2012