Почему подклассы ndb.Model расширяются при заполнении?

У нас есть модель, определенная как ...

class Foo(ndb.Model): bar = ndb.TextProperty()

Если я создам, или get, экземпляр Foo и назову его foo, это сработает ...

foo.populate(**{'SPAM': None})

Это дает foo новое свойство SPAM.

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

Для записи, новые свойства тоже нетипизированы, поэтому я могу сделать SPAM 5, а затем "five", без проблем.


person Carl Smith    schedule 24.02.2014    source источник


Ответы (3)


Я почти уверен, что это сделано специально. Вы можете делать все, что хотите, с объектом foo, например, вы можете присвоить целочисленные значения и объекту bar и даже удалить это свойство, если хотите. Но когда дело доходит до сохранения этого значения, в нем будут храниться только те свойства, которые определены в модели и имеют правильный тип. Исключение будет вызвано только в том случае, если тип или значение существующих свойств не соответствуют их определению.

person Lipis    schedule 24.02.2014
comment
То, что вы говорите, правда; вот как это работает, но в этом случае данные были помещены в базу данных и получены позже, поэтому они не только были привязаны к экземпляру, но и были сохранены. - person Carl Smith; 25.02.2014

Выполнение опубликованного кода вызовет ошибку TypeError, поскольку populate ожидает аргументы ключевого слова, которые соответствуют именам свойств, а не dict. Колл foo.populate(**{"SPAM": None}) или foo.populate(SPAM=None) повысит

AttributeError: type object 'Foo' has no attribute 'SPAM'

Вы уверены, что ваш реальный код не отличается от вашего примера? (Возможно, ваши модели являются подклассами Expando?)

person Greg    schedule 24.02.2014
comment
Вы правы, я забыл использовать ** для расширения kargs в примере, я это исправил. - person Carl Smith; 25.02.2014

Грег сказал: «Может быть, ваши модели являются подклассами Expando?» Это то, о чем я спрашивал себя сначала, но в реальном коде ndb.Model был базовым классом, который мы использовали для всего остального.

Модель приложения User фактически взята из библиотеки аутентификации, которую мы использовали, webapp2_extras.appengine.auth.models, которая предположительно использует базовый класс Expando.

Я тестировал эту и все остальные модели, которые выдают ожидаемое исключение.

TL; DR Модель User в webapp2_extras.appengine.auth.models использует Expando базовый класс. Никакой настоящей загадки.

person Carl Smith    schedule 24.02.2014