Запрос хранилища данных без класса модели - PullRequest
0 голосов
/ 27 февраля 2019

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

Я не смог найти какой-либо готовый способ сделать это с помощью пакета google.appengine.ext.db, поэтому я в итоге использовал google.appengine.api.datastore.Queryкласс из нижнего уровня datastore API .

Это отлично работало для моих нужд (моему запросу нужно было только подсчитать количество результатов, не возвращая экземпляров модели), но мне было интересно, знает ли кто-нибудь о лучшем решении.

ДругоеПодход, который я пробовал (который также работал), заключался в создании подкласса db.GqlQuery, чтобы обойти его конструктор.Возможно, это не самое чистое решение, но если кому-то интересно, вот код:

import logging
from google.appengine.ext import db, gql

class ClasslessGqlQuery(db.GqlQuery):
  """
  This subclass of :class:`db.GqlQuery` uses a modified version of ``db.GqlQuery``'s constructor to suppress any
  :class:`db.KindError` that might be raised by ``db.class_for_kind(kindName)``.

  This allows using the functionality :class:`db.GqlQuery` without requiring that a Model class for the query's kind
  be available in the local environment, which could happen if a module defining that class hasn't been imported yet.
  In that case, no validation of the Model's properties will be performed (will not check whether they're not indexed),
  but otherwise, this class should work the same as :class:`db.GqlQuery`.
  """

  def __init__(self, query_string, *args, **kwds):
    """
    **NOTE**: this is a modified version of :class:`db.GqlQuery`'s constructor, suppressing any :class:`db.KindError`s
    that might be raised by ``db.class_for_kind(kindName)``.
    In that case, no validation of the Model's properties will be performed (will not check whether they're not indexed),
    but otherwise, this class should work the same as :class:`db.GqlQuery`.

    Args:
      query_string: Properly formatted GQL query string.
      *args: Positional arguments used to bind numeric references in the query.
      **kwds: Dictionary-based arguments for named references.

    Raises:
      PropertyError if the query filters or sorts on a property that's not indexed.
    """
    from google.appengine.ext import gql
    app = kwds.pop('_app', None)
    namespace = None
    if isinstance(app, tuple):
      if len(app) != 2:
        raise db.BadArgumentError('_app must have 2 values if type is tuple.')
      app, namespace = app

    self._proto_query = gql.GQL(query_string, _app=app, namespace=namespace)
    kind = self._proto_query._kind
    model_class = None
    try:
      if kind is not None:
        model_class = db.class_for_kind(kind)
    except db.KindError, e:
      logging.warning("%s on %s without a model class", self.__class__.__name__, kind, exc_info=True)

    super(db.GqlQuery, self).__init__(model_class)

    if model_class is not None:
      for property, unused in (self._proto_query.filters().keys() +
                               self._proto_query.orderings()):
        if property in model_class._unindexed_properties:
          raise db.PropertyError('Property \'%s\' is not indexed' % property)

    self.bind(*args, **kwds)

( также доступен в виде сущности )

1 Ответ

0 голосов
/ 27 февраля 2019

Вы можете создать временный класс просто для выполнения запроса.Если вы используете модель Expando, свойства класса не должны совпадать с тем, что на самом деле находится в хранилище данных.

class KindName(ndb.Expando):
    pass

Затем вы можете сделать:

KindName.query()

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

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