0

я объявил 2 модели Ndb следующим образом:Ndb модели пользовательское свойство не возвращает правильное значение при развертывании

class Event(ndb.Model): 
    event_type = ndb.KeyProperty() 

    @property 
    def installments(self): 
     return EventInstallment.query().filter(EventInstallment.event == self.key).count() 

class EventInstallment(ndb.Model): 
    event = ndb.KeyProperty() 

я настойчив единое целое типа Event и другого типа EventInstallment. EventInstallment.event - это ключ объявленной сущности Event. Следующий запрос работает (т.е. возвращает 1) при запуске локально, но не при развертывании:

event_query = Event.query() 
event_query = event_query.filter(ndb.GenericProperty('installments') > 0) 
print event_query.count() 

я очистил кэш памяти, и проверил, что все свойства EventInstallment являются правильными. При открытии объекта EventInstallment в datastoreviewer он имеет горячую ссылку на ключ Event, как и ожидалось.

Может кто-нибудь сказать мне, что здесь происходит не так? В частности, мне любопытно узнать, почему это работает локально, а не при развертывании.

+0

Сколько времени между вами, '.put()' объект 'EventInstallment' и когда выполняется ваш второй фрагмент кода? –

+0

Хорошо - в тестировании это было где угодно до 30 минут - я не думаю, что это был вопрос времени. – user714852

+1

Также обратите внимание, что ... если вы просто хотите, чтобы подсчет результатов запроса извлекал только ключи (.count (keys_only = True) – janscas

ответ

2

filter должен быть в состоянии работать в хранилище данных, и, в развернутом приложении, filter(ndb.GenericProperty('installments') > 0) явно не может (моделирование dev_appserver делает это не 100% точным, я держал пари, его авторы не мечтал проверить что-то в этом роде).

Скорее всего, вы хотите получить ComputedProperty, который вычисляется и отправляется в хранилище данных по адресу put, что позволяет хранилищу выполнять поиск на нем. Для остроумие:

class Event(ndb.Model): 
    event_type = ndb.KeyProperty() 

    @property 
    def _installments(self): 
     return EventInstallment.query().filter(EventInstallment.event == self.key).count() 

    installments = ndb.ComputedProperty(lambda self: self._installments) 

Теперь filter(Event.installments > 0) будет работать - до тех пор, как количество связанных с EventInstallment лиц в момент Event лицо было последним put был положительным. (Хранилище данных не будет повторно запускать код для обновления Event объектов, когда EventInstallment объекты добавляются, удаляются или изменяются; ComputedProperty вычисляется по адресу put времени на сущности, к которой он принадлежит, и вычисляется на стороне экземпляра приложения, т.е. в «коде уровня приложения», непосредственно перед отправкой сущности на сторону хранилища данных).

Вы можете работать в другую сторону «круглый: запрос для EventInstallment лиц, что делает набор их event свойств для удаления дубликатов и используя len этого набора в качестве требуемого счета. Да, это требует выборки всех из них, но подсчет не намного быстрее, чем выборка.

+0

Спасибо за всесторонний ответ. Да - причина, по которой я использую настраиваемое свойство, - это то, что больше платежей получают добавлено с течением времени, поэтому мне нужен простой способ запросить количество платежей за событие. Именно по этой причине я никогда не использовал ComputedProperty - так как число со временем должно меняться. – user714852

+0

Как и для выборки vs count, у меня создалось впечатление, что fetch довольно дорого, в то время как количество намного дешевле с точки зрения чтения? – user714852

+0

@ user714852, номер будет ** не ** автоматически «меняться со временем» * в хранилище данных *, где это важно для запросов, с любым видом свойство (вид, который вы использовали, вообще не отправляется в хранилище ** **). 'count' только скромнее дешевле, чем' fetch' (с запросом проекции, получающим только одно поле, или, если возможно, только ключи , если сущности a большой; сущность, которую вы показываете, очень мала, так что не имеет большого значения). В качестве альтернативы вы можете денормализовать модель, сохранить счетчик на событии и увеличить его (транзакционно, если это необходимо) при добавлении платежей. Но, транзакция = медленнее. –

 Смежные вопросы

  • Нет связанных вопросов^_^