Ошибка в GAE с ndb - BadQueryError: невозможно преобразовать FalseNode в предикат

У меня есть приложение, работающее в Google App Engine с python. Классы моделей распространяются от классов ndb (google.appengine.ext.ndb).

Один из моих просмотров делает асинхронные вызовы в базе данных, что-то более или менее похожее:

# ExerciseListLog is a ndb model class
# start_current, end_current are dates
# student_id is a string
# contents is a list of keys

exercise_log_query = ExerciseListLog.query(ndb.AND(ExerciseListLog.creation >= start_current,
    ExerciseListLog.creation < end_current,
    ExerciseListLog.user_id == student_id))
exercise_log_query = exercise_log_query.filter(ExerciseListLog.content.IN(contents))

future = exercise_log_query.count_async()

count = future.get_result() # this throws BadQueryError

это вызывает ошибку на get_result(): BadQueryError: Невозможно преобразовать FalseNode в предикат

Но это происходит только при развертывании моего кода в облаке Google. Когда я запускаю его локально, он отлично работает.

Я понятия не имею, что означает эта ошибка, и поиск ее в Google не очень помогает. Кто-нибудь знает, что здесь не так?

Здесь полный стек из журналов GAE

Traceback (most recent call last):
  File "/base/data/home/apps/s~qmagtest/1.366092357976105290/zen/web/gae/convention.py", line 48, in make_convention
    method(*args, **kwargs)
  File "/base/data/home/apps/s~qmagtest/1.366092357976105290/core/web/qmhandler.py", line 48, in wrapper
    return method(self, *args, **kwargs)
  File "/base/data/home/apps/s~qmagtest/1.366092357976105290/core/user/login/security.py", line 36, in wrapper
    method(self, *args, **kwargs)
  File "/base/data/home/apps/s~qmagtest/1.366092357976105290/core/user/security.py", line 17, in wrapper
    method(self, *args_inner, **kwargs)
  File "/base/data/home/apps/s~qmagtest/1.366092357976105290/plugins/web/desempenho/estatisticas.py", line 127, in class_activities
    school_class.content)
  File "/base/data/home/apps/s~qmagtest/1.366092357976105290/plugins/web/desempenho/estatisticas.py", line 178, in _get_exercise_video_and_total_weekly_series
    exercise_log_count = exercise_count_futures[i].get_result()
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 325, in get_result
    self.check_success()
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 371, in _help_tasklet_along
    value = gen.send(val)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/query.py", line 1227, in _count_async
    dsquery = self._get_query(conn)
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/query.py", line 873, in _get_query
    filters = filters._to_filter()
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/query.py", line 599, in _to_filter
    for node in self.__nodes
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/query.py", line 600, in <genexpr>
    if isinstance(node, PostFilterNode) == post))
  File "/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/query.py", line 425, in _to_filter
    'Cannot convert FalseNode to predicate')
BadQueryError: Cannot convert FalseNode to predicate

Ответ 1

Я подозреваю, что проблема заключается в том, что содержимое представляет собой пустой список. Это почти единственная причина, по которой FalseNode может появиться. (Другой вызывает AND() без аргументов.) Ваше наблюдение, что удаление этой строки подтверждает мою догадку. Вероятно, вы не ожидали, что это произойдет, и в ваших локальных тестах это никогда не происходило. Вероятно, вам нужно отладить код, который появляется в этом списке.

Я согласен с тем, что сообщение об ошибке может быть лучше.

Ответ 2

Update:

Я выяснил, что если я удалю строку:

exercise_log_query = exercise_log_query.filter(ExerciseListLog.content.IN(contents))

Тогда он будет работать.

Таким образом, ошибка не имеет ничего общего с асинхронным вызовом базы данных. Это происходит потому, что Google AppEngine поддерживает фильтры неравенства только в одном поле для каждого запроса. По-видимому, использование "content.IN" считается вторым неравенством, которое не допускается.

Это сообщение об ошибке может быть лучше.


UPDATE:

Оказывается, Гвидо прав, и мое объяснение выше НЕПРАВИЛЬНО. content.IN теперь работает, когда contents не пуст.