Как построить запрос динамически, основываясь на условиях?
Я хочу запросить хранилище данных по диапазону (0-4) возможных критериев, основываясь на запросе пользователя. Запросы в NDB строятся следующим образом:
query = Account.query(Account.userid >= 40, Account.userid < 50)
Есть ли способ, которым я мог бы сделать что-то вроде:
myfilter = []
myfilter.push('Account.userid >= 40')
myfilter.push('Account.userid < 50')
myfilter.push('Account.name == "John"')
query = Account.query(*myfilter)
Может быть от 0 до 4 аргументов фильтра, в зависимости от условий. Мое предположение (которое может быть неверным) состоит в том, что более оптимально пропустить фильтр, чем иметь всеохватывающий (напр. Счет.userid == *) если в этом нет необходимости.
Я знаю, что вы можете цеплять фильтры но так как объекты запроса неизменяемы, не уверен, что это поможет мне.
2 ответа:
Да, это возможно. Из фильтрация по значениям свойств:
Вместо указания всего фильтра запроса в одном выражении, возможно, Вам будет удобнее построить его поэтапно: например:
query1 = Account.query() # Retrieve all Account entitites query2 = query1.filter(Account.userid >= 40) # Filter on userid >= 40 query3 = query2.filter(Account.userid < 50) # Filter on userid < 50 too
query3эквивалентна переменнойqueryиз предыдущей образец. Обратите внимание, что объекты запроса являются неизменяемыми, поэтому построениеquery2не влияет наquery1и построениеquery3не влияет наquery1илиquery2.Вы можете использовать такой метод построения инкрементных запросов для условного добавления фильтров по мере необходимости. Например (это предполагает общее и между необязательными условиями):
Приведенный выше фрагмент кода специально использует преимущества имутативности объекта запроса, каждое назначение переменнойquery = Account.query() # Retrieve all Account entitites loggin.error(query) if filter_by_userid: query = query.filter(Account.userid >= 40, Account.userid < 50) loggin.error(query) if filter_by_username: query = query.filter(Account.name == "John") loggin.error(query) loggin.error('Final: %s' % query)queryфактически сохраняет новый объект запроса , полученный путем применения соответствующего фильтра. Подтверждается соответствующими сообщениями журнала.
Есть более элегантный способ сделать это. И кстати более динамично:
def build_query_by(ndb_class, filters, sorts): """ ndb_class: the ndb model class to query filters: a list of tuples of properties, operations and values sorts: a list of tuples of properties and order symbol """ q = ndb_class.query() for prop, operation, value in filters: if operation == '==': q = q.filter(getattr(ndb_class, prop) == value) elif operation == '>=': q = q.filter(getattr(ndb_class, prop) >= value) elif operation == '<=': q = q.filter(getattr(ndb_class, prop) <= value) # more operations... for prop, symbol in sorts: if symbol == '-': q = q.order(-getattr(ndb_class, prop)) else: q = q.order(getattr(ndb_class, prop)) return q