def setUp(self): add_special_index(User, "username", "iexact") User.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) User.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) User.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) User.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) User.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date())
def setUp(self): add_special_index(TestUser, "username", "iexact") self.u1 = TestUser.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) self.u2 = TestUser.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) TestUser.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) TestUser.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) TestUser.objects.create(username="******", email="*****@*****.**", last_login=datetime.datetime.now().date()) self.apple = TestFruit.objects.create(name="apple", color="red") self.banana = TestFruit.objects.create(name="banana", color="yellow")
def parse_constraint(child, connection, negated=False): #First, unpack the constraint constraint, op, annotation, value = child was_list = isinstance(value, (list, tuple)) packed, value = constraint.process(op, value, connection) alias, column, db_type = packed if constraint.field.db_type(connection) in ("bytes", "text"): raise NotSupportedError("Text and Blob fields are not indexed by the datastore, so you can't filter on them") if op not in REQUIRES_SPECIAL_INDEXES: #Don't convert if this op requires special indexes, it will be handled there value = [ connection.ops.prep_lookup_value(constraint.field.model, x, constraint.field, constraint=constraint) for x in value] #Don't ask me why, but constraint.process on isnull wipes out the value (it returns an empty list) # so we have to special case this to use the annotation value instead if op == "isnull": value = [ annotation ] if constraint.field.primary_key and value[0]: raise EmptyResultSet() if not was_list: value = value[0] else: if negated: raise CouldBeSupportedError("Special indexing does not currently supported negated queries. See #80") if not was_list: value = value[0] add_special_index(constraint.field.model, column, op) #Add the index if we can (e.g. on dev_appserver) if op not in special_indexes_for_column(constraint.field.model, column): raise RuntimeError("There is a missing index in your djangaeidx.yaml - \n\n{0}:\n\t{1}: [{2}]".format( constraint.field.model, column, op) ) indexer = REQUIRES_SPECIAL_INDEXES[op] column = indexer.indexed_column_name(column) value = indexer.prep_value_for_query(value) op = indexer.prep_query_operator(op) return column, op, value
def parse_constraint(child, connection): #First, unpack the constraint constraint, op, annotation, value = child was_list = isinstance(value, (list, tuple)) packed, value = constraint.process(op, value, connection) alias, column, db_type = packed if constraint.field.db_type(connection) in ("bytes", "text"): raise NotSupportedError("Text and Blob fields are not indexed by the datastore, so you can't filter on them") if op not in REQUIRES_SPECIAL_INDEXES: #Don't convert if this op requires special indexes, it will be handled there value = [ connection.ops.prep_lookup_value(constraint.field.model, x, constraint.field, constraint=constraint) for x in value] #Don't ask me why, but constraint.process on isnull wipes out the value (it returns an empty list) # so we have to special case this to use the annotation value instead if op == "isnull": value = [ annotation ] if not was_list: value = value[0] else: if not was_list: value = value[0] add_special_index(constraint.field.model, column, op) #Add the index if we can (e.g. on dev_appserver) if op not in special_indexes_for_column(constraint.field.model, column): raise RuntimeError("There is a missing index in your djangaeidx.yaml - \n\n{0}:\n\t{1}: [{2}]".format( constraint.field.model, column, op) ) indexer = REQUIRES_SPECIAL_INDEXES[op] column = indexer.indexed_column_name(column) value = indexer.prep_value_for_query(value) op = indexer.prep_query_operator(op) return column, op, value
def parse_constraint(child, connection, negated=False): if isinstance(child, tuple): # First, unpack the constraint constraint, op, annotation, value = child was_list = isinstance(value, (list, tuple)) if isinstance(value, query.Query): value = value.get_compiler(connection.alias).as_sql()[0].execute() else: packed, value = constraint.process(op, value, connection) alias, column, db_type = packed field = constraint.field else: # Django 1.7+ field = child.lhs.target column = child.lhs.target.column op = child.lookup_name value = child.rhs annotation = value was_list = isinstance(value, (list, tuple)) if isinstance(value, query.Query): value = value.get_compiler(connection.alias).as_sql()[0].execute() elif value != []: value = child.lhs.output_field.get_db_prep_lookup( child.lookup_name, child.rhs, connection, prepared=True) is_pk = field and field.primary_key if column == "id" and op == "iexact" and is_pk and isinstance(field, AutoField): # When new instance is created, automatic primary key 'id' does not generate '_idx_iexact_id'. # As the primary key 'id' (AutoField) is integer and is always case insensitive, we can deal with 'id_iexact=' query by using 'exact' rather than 'iexact'. op = "exact" if field and field.db_type(connection) in ("bytes", "text"): raise NotSupportedError("Text and Blob fields are not indexed by the datastore, so you can't filter on them") if op not in REQUIRES_SPECIAL_INDEXES: # Don't convert if this op requires special indexes, it will be handled there if field: value = [ connection.ops.prep_lookup_value(field.model, x, field, column=column) for x in value] # Don't ask me why, but on Django 1.6 constraint.process on isnull wipes out the value (it returns an empty list) # so we have to special case this to use the annotation value instead if op == "isnull": if annotation is not None: value = [ annotation ] if is_pk and value[0]: raise EmptyResultSet() if not was_list: value = value[0] else: if negated: raise CouldBeSupportedError("Special indexing does not currently supported negated queries. See #80") if not was_list: value = value[0] add_special_index(field.model, column, op) # Add the index if we can (e.g. on dev_appserver) if op not in special_indexes_for_column(field.model, column): raise RuntimeError("There is a missing index in your djangaeidx.yaml - \n\n{0}:\n\t{1}: [{2}]".format( field.model, column, op) ) indexer = REQUIRES_SPECIAL_INDEXES[op] value = indexer.prep_value_for_query(value) column = indexer.indexed_column_name(column, value=value) op = indexer.prep_query_operator(op) return column, op, value
def _build_gae_query(self): """ Build and return the Datstore Query object. """ combined_filters = [] query_kwargs = {} if self.keys_only: query_kwargs["keys_only"] = self.keys_only elif self.projection: query_kwargs["projection"] = self.projection query = Query( self.db_table, **query_kwargs ) if has_concrete_parents(self.model) and not self.model._meta.proxy: query["class ="] = self.model._meta.db_table DJANGAE_LOG.debug("Select query: {0}, {1}".format(self.model.__name__, self.where)) for column, op, value in self.where: if column == self.pk_col: column = "__key__" final_op = OPERATORS_MAP.get(op) if final_op is None: if op in REQUIRES_SPECIAL_INDEXES: add_special_index(self.model, column, op) #Add the index if we can (e.g. on dev_appserver) if op not in special_indexes_for_column(self.model, column): raise RuntimeError("There is a missing index in your djangaeidx.yaml - \n\n{0}:\n\t{1}: [{2}]".format( self.model, column, op) ) indexer = REQUIRES_SPECIAL_INDEXES[op] column = indexer.indexed_column_name(column) value = indexer.prep_value_for_query(value) query["%s =" % column] = value else: if op == "in": combined_filters.append((column, op, value)) elif op == "gt_and_lt": combined_filters.append((column, op, value)) elif op == "isnull": query["%s =" % column] = None elif op == "startswith": #You can emulate starts with by adding the last unicode char #to the value, then doing <=. Genius. query["%s >=" % column] = value if isinstance(value, str): value = value.decode("utf-8") value += u'\ufffd' query["%s <=" % column] = value else: raise NotImplementedError("Unimplemented operator {0}".format(op)) else: query["%s %s" % (column, final_op)] = value ordering = [] for order in self.ordering: if isinstance(order, int): direction = datastore.Query.ASCENDING if order == 1 else datastore.Query.DESCENDING order = self.queried_fields[0] else: direction = datastore.Query.DESCENDING if order.startswith("-") else datastore.Query.ASCENDING order = order.lstrip("-") if order == self.model._meta.pk.column: order = "__key__" ordering.append((order, direction)) if combined_filters: queries = [ query ] for column, op, value in combined_filters: new_queries = [] for query in queries: if op == "in": for val in value: new_query = datastore.Query(self.model._meta.db_table) new_query.update(query) new_query["%s =" % column] = val new_queries.append(new_query) elif op == "gt_and_lt": for tmp_op in ("<", ">"): new_query = datastore.Query(self.model._meta.db_table) new_query.update(query) new_query["%s %s" % (column, tmp_op)] = value new_queries.append(new_query) queries = new_queries query = datastore.MultiQuery(queries, ordering) elif ordering: query.Order(*ordering) return query