def _get_field(model, name): from django.db.models.fields import FieldDoesNotExist # Create a fake query object so we can easily work out what field # type we are dealing with qs = Query(model) opts = qs.get_meta() alias = qs.get_initial_alias() parts = name.split(LOOKUP_SEP) # The following is borrowed from the innards of Query.add_filter - it strips out __gt, __exact et al. num_parts = len(parts) if num_parts > 1 and parts[-1] in qs.query_terms: # Traverse the lookup query to distinguish related fields from # lookup types. for counter, field_name in enumerate(parts, 1): try: lookup_field = model._meta.get_field(field_name) except FieldDoesNotExist: # Not a field. Bail out. parts.pop() break # Unless we're at the end of the list of lookups, let's attempt # to continue traversing relations. if counter < num_parts: try: model = lookup_field.rel.to except AttributeError: # Not a related field. Bail out. parts.pop() break return resolve_field(qs, parts, opts, alias)
def test_filter_conditional(self): query = Query(Item) where = query.build_where(Func(output_field=BooleanField())) exact = where.children[0] self.assertIsInstance(exact, Exact) self.assertIsInstance(exact.lhs, Func) self.assertIs(exact.rhs, True)
def __init__(self, model, query=None, using=None): # the model needs to be defined so that we can construct our custom # query if query is None: query = Query(model) query.add_q(models.Q(effective_to__isnull=True)) return super(ActiveQuerySet, self).__init__(model, query, using)
def resolve_lookup(self, model_cls: Type[Model], lookup: str) -> Field: query = Query(model_cls) lookup_parts, field_parts, is_expression = query.solve_lookup_type( lookup) if lookup_parts: raise FieldError('Lookups not supported yet') currently_observed_model = model_cls current_field = None for field_part in field_parts: if field_part == 'pk': return self.django_context.get_primary_key_field( currently_observed_model) current_field = currently_observed_model._meta.get_field( field_part) if not isinstance(current_field, (ForeignObjectRel, RelatedField)): continue currently_observed_model = self.django_context.fields_context.get_related_model_cls( current_field) if isinstance(current_field, ForeignObjectRel): current_field = self.django_context.get_primary_key_field( currently_observed_model) # if it is None, solve_lookup_type() will fail earlier assert current_field is not None return current_field
def resolve_lookup_into_field(self, model_cls: Type[Model], lookup: str) -> Union[Field, ForeignObjectRel]: query = Query(model_cls) lookup_parts, field_parts, is_expression = query.solve_lookup_type(lookup) if lookup_parts: raise LookupsAreUnsupported() return self._resolve_field_from_parts(field_parts, model_cls)
def _get_field(model, name): # Create a fake query object so we can easily work out what field # type we are dealing with qs = Query(model) parts = name.split(LOOKUP_SEP) # The following is borrowed from the innards of Query.add_filter - it strips out __gt, __exact et al. num_parts = len(parts) if num_parts > 1 and parts[-1] in QUERY_TERMS: # Traverse the lookup query to distinguish related fields from # lookup types. for counter, field_name in enumerate(parts, 1): try: lookup_field = model._meta.get_field(field_name) except FieldDoesNotExist: # Not a field. Bail out. parts.pop() break # Unless we're at the end of the list of lookups, let's attempt # to continue traversing relations. if counter < num_parts: try: model = lookup_field.rel.to except AttributeError: # Not a related field. Bail out. parts.pop() break return qs.names_to_path(parts, qs.get_meta(), True, fail_on_missing=False)[1]
def test_simple_query(self): query = Query(Author) where = query.build_where(Q(num__gt=2)) lookup = where.children[0] self.assertIsInstance(lookup, GreaterThan) self.assertEqual(lookup.rhs, 2) self.assertEqual(lookup.lhs.target, Author._meta.get_field('num'))
def _get_field(model, name): # Create a fake query object so we can easily work out what field # type we are dealing with parts = name.split(LOOKUP_SEP) # The following is borrowed from the innards of Query.add_filter - it strips out __gt, __exact et al. num_parts = len(parts) if num_parts > 1 and parts[-1] in Query.query_terms: # Traverse the lookup query to distinguish related fields from # lookup types. for counter, field_name in enumerate(parts, 1): try: lookup_field = model._meta.get_field(field_name) except FieldDoesNotExist: # Not a field. Bail out. parts.pop() break # Unless we're at the end of the list of lookups, let's attempt # to continue traversing relations. if counter < num_parts: try: model = lookup_field.rel.to except AttributeError: # Not a related field. Bail out. parts.pop() break qs = Query(model) return qs.names_to_path(parts, qs.get_meta(), True, fail_on_missing=False)[1]
def _get_condition_sql(self, model, schema_editor): if self.condition is None: return None query = Query(model=model) where = query.build_where(self.condition) compiler = query.get_compiler(connection=schema_editor.connection) sql, params = where.as_sql(compiler, schema_editor.connection) return sql % tuple(schema_editor.quote_value(p) for p in params)
def constraint_sql(self, model, schema_editor): query = Query(model) where = query.build_where(self.check) connection = schema_editor.connection compiler = connection.ops.compiler('SQLCompiler')(query, connection, 'default') sql, params = where.as_sql(compiler, connection) params = tuple(schema_editor.quote_value(p) for p in params) return schema_editor.sql_check_constraint % {'check': sql % params}
def _get_condition_sql(self, model, schema_editor): if self.condition is None: return None query = Query(model=model, alias_cols=False) where = query.build_where(self.condition) compiler = query.get_compiler(connection=schema_editor.connection) sql, params = where.as_sql(compiler, schema_editor.connection) return sql % tuple(schema_editor.quote_value(p) for p in params)
def test_multiple_fields(self): query = Query(Item) where = query.build_where(Q(modified__gt=F('created'))) lookup = where.children[0] self.assertIsInstance(lookup, GreaterThan) self.assertIsInstance(lookup.rhs, SimpleCol) self.assertIsInstance(lookup.lhs, SimpleCol) self.assertEqual(lookup.rhs.target, Item._meta.get_field('created')) self.assertEqual(lookup.lhs.target, Item._meta.get_field('modified'))
def follow_model_field_lookup(model, lookup): """ Follow a model lookup `foreignkey__foreignkey__field` in the same way that Django QuerySet.filter() does, returning the final models.Field. """ query = Query(model) lookup_splitted = lookup.split(LOOKUP_SEP) _, field, _, _ = query.names_to_path(lookup_splitted, query.get_meta()) return field
def test_transform(self): query = Query(Author) with register_lookup(CharField, Lower): where = query.build_where(~Q(name__lower='foo')) lookup = where.children[0] self.assertIsInstance(lookup, Exact) self.assertIsInstance(lookup.lhs, Lower) self.assertIsInstance(lookup.lhs.lhs, SimpleCol) self.assertEqual(lookup.lhs.lhs.target, Author._meta.get_field('name'))
def test_q_annotation(self): query = Query(None) check = ExpressionWrapper( Q(RawSQL("%s IS NULL", (None, ), BooleanField())) | Q(Exists(Item.objects.all())), BooleanField(), ) query.add_annotation(check, "_check") result = query.get_compiler(using=DEFAULT_DB_ALIAS).execute_sql(SINGLE) self.assertEqual(result[0], 1)
def test_negated_nullable(self): query = Query(Item) where = query.build_where(~Q(modified__lt=datetime(2017, 1, 1))) self.assertTrue(where.negated) lookup = where.children[0] self.assertIsInstance(lookup, LessThan) self.assertEqual(lookup.lhs.target, Item._meta.get_field('modified')) lookup = where.children[1] self.assertIsInstance(lookup, IsNull) self.assertEqual(lookup.lhs.target, Item._meta.get_field('modified'))
def test_names_to_path_field(self): query = Query(None) query.add_annotation(Value(True), "value") path, final_field, targets, names = query.names_to_path(["value"], opts=None) self.assertEqual(path, []) self.assertIsInstance(final_field, BooleanField) self.assertEqual(len(targets), 1) self.assertIsInstance(targets[0], BooleanField) self.assertEqual(names, [])
def test_rawsql_annotation(self): query = Query(None) sql = "%s IS NULL" # Wrap with a CASE WHEN expression if a database backend (e.g. Oracle) # doesn't support boolean expression in SELECT list. if not connection.features.supports_boolean_expr_in_select_clause: sql = f"CASE WHEN {sql} THEN 1 ELSE 0 END" query.add_annotation(RawSQL(sql, (None, ), BooleanField()), "_check") result = query.get_compiler(using=DEFAULT_DB_ALIAS).execute_sql(SINGLE) self.assertEqual(result[0], 1)
def test_transform(self): query = Query(Author, alias_cols=False) with register_lookup(CharField, Lower): where = query.build_where(~Q(name__lower="foo")) lookup = where.children[0] self.assertIsInstance(lookup, Exact) self.assertIsInstance(lookup.lhs, Lower) self.assertIsInstance(lookup.lhs.lhs, Col) self.assertIsNone(lookup.lhs.lhs.alias) self.assertEqual(lookup.lhs.lhs.target, Author._meta.get_field("name"))
def test_foreign_key_exclusive(self): query = Query(ObjectC) where = query.build_where(Q(objecta=None) | Q(objectb=None)) a_isnull = where.children[0] self.assertIsInstance(a_isnull, RelatedIsNull) self.assertIsInstance(a_isnull.lhs, SimpleCol) self.assertEqual(a_isnull.lhs.target, ObjectC._meta.get_field('objecta')) b_isnull = where.children[1] self.assertIsInstance(b_isnull, RelatedIsNull) self.assertIsInstance(b_isnull.lhs, SimpleCol) self.assertEqual(b_isnull.lhs.target, ObjectC._meta.get_field('objectb'))
def test_multiple_fields(self): query = Query(Item, alias_cols=False) where = query.build_where(Q(modified__gt=F("created"))) lookup = where.children[0] self.assertIsInstance(lookup, GreaterThan) self.assertIsInstance(lookup.rhs, Col) self.assertIsNone(lookup.rhs.alias) self.assertIsInstance(lookup.lhs, Col) self.assertIsNone(lookup.lhs.alias) self.assertEqual(lookup.rhs.target, Item._meta.get_field("created")) self.assertEqual(lookup.lhs.target, Item._meta.get_field("modified"))
def resolve_lookup_expected_type(self, ctx: MethodContext, model_cls: Type[Model], lookup: str) -> MypyType: query = Query(model_cls) try: lookup_parts, field_parts, is_expression = query.solve_lookup_type( lookup) if is_expression: return AnyType(TypeOfAny.explicit) except FieldError as exc: ctx.api.fail(exc.args[0], ctx.context) return AnyType(TypeOfAny.from_error) field = self._resolve_field_from_parts(field_parts, model_cls) lookup_cls = None if lookup_parts: lookup = lookup_parts[-1] lookup_cls = field.get_lookup(lookup) if lookup_cls is None: # unknown lookup return AnyType(TypeOfAny.explicit) if lookup_cls is None or isinstance(lookup_cls, Exact): return self.get_field_lookup_exact_type( helpers.get_typechecker_api(ctx), field) assert lookup_cls is not None lookup_info = helpers.lookup_class_typeinfo( helpers.get_typechecker_api(ctx), lookup_cls) if lookup_info is None: return AnyType(TypeOfAny.explicit) for lookup_base in helpers.iter_bases(lookup_info): if lookup_base.args and isinstance(lookup_base.args[0], Instance): lookup_type: MypyType = lookup_base.args[0] # if it's Field, consider lookup_type a __get__ of current field if (isinstance(lookup_type, Instance) and lookup_type.type.fullname() == fullnames.FIELD_FULLNAME): field_info = helpers.lookup_class_typeinfo( helpers.get_typechecker_api(ctx), field.__class__) if field_info is None: return AnyType(TypeOfAny.explicit) lookup_type = helpers.get_private_descriptor_type( field_info, '_pyi_private_get_type', is_nullable=field.null) return lookup_type return AnyType(TypeOfAny.explicit)
def test_foreign_key_exclusive(self): query = Query(ObjectC, alias_cols=False) where = query.build_where(Q(objecta=None) | Q(objectb=None)) a_isnull = where.children[0] self.assertIsInstance(a_isnull, RelatedIsNull) self.assertIsInstance(a_isnull.lhs, Col) self.assertIsNone(a_isnull.lhs.alias) self.assertEqual(a_isnull.lhs.target, ObjectC._meta.get_field("objecta")) b_isnull = where.children[1] self.assertIsInstance(b_isnull, RelatedIsNull) self.assertIsInstance(b_isnull.lhs, Col) self.assertIsNone(b_isnull.lhs.alias) self.assertEqual(b_isnull.lhs.target, ObjectC._meta.get_field("objectb"))
def test_simplecol_query(self): query = Query(Author) where = query.build_where(Q(num__gt=2, name__isnull=False) | Q(num__lt=F('id'))) name_isnull_lookup, num_gt_lookup = where.children[0].children self.assertIsInstance(num_gt_lookup, GreaterThan) self.assertIsInstance(num_gt_lookup.lhs, SimpleCol) self.assertIsInstance(name_isnull_lookup, IsNull) self.assertIsInstance(name_isnull_lookup.lhs, SimpleCol) num_lt_lookup = where.children[1] self.assertIsInstance(num_lt_lookup, LessThan) self.assertIsInstance(num_lt_lookup.rhs, SimpleCol) self.assertIsInstance(num_lt_lookup.lhs, SimpleCol)
def test_complex_query(self): query = Query(Author) where = query.build_where(Q(num__gt=2) | Q(num__lt=0)) self.assertEqual(where.connector, OR) lookup = where.children[0] self.assertIsInstance(lookup, GreaterThan) self.assertEqual(lookup.rhs, 2) self.assertEqual(lookup.lhs.target, Author._meta.get_field('num')) lookup = where.children[1] self.assertIsInstance(lookup, LessThan) self.assertEqual(lookup.rhs, 0) self.assertEqual(lookup.lhs.target, Author._meta.get_field('num'))
def get_related_decrement_value(self, using): qn = self.get_quote_name(using) related_query = Query(self.manager.related.model) related_query.add_extra(None, None, [ "%s = %s.%s" % (qn(self.model._meta.pk.get_attname_column()[1]), 'OLD', qn(self.manager.related.field.m2m_column_name())) ], None, None, None) related_query.add_fields([self.fieldname]) related_query.clear_ordering(force_empty=True) related_query.default_cols = False related_filter_where, related_where_params = related_query.get_compiler( using=using).as_sql() return "%s - (%s)" % (qn(self.fieldname), related_filter_where)
def get_related_decrement_value(self, using): qn = self.get_quote_name(using) related_query = Query(self.manager.related.model) related_query.add_extra(None, None, ["%s = %s.%s" % (qn(self.model._meta.pk.get_attname_column()[1]), 'OLD', qn(self.manager.related.field.m2m_column_name()))], None, None, None) related_query.add_fields([self.fieldname]) related_query.clear_ordering(force_empty=True) related_query.default_cols = False related_filter_where, related_where_params = related_query.get_compiler(using=using).as_sql() return "%s - (%s)" % (qn(self.fieldname), related_filter_where)
def test_non_alias_cols_query(self): query = Query(Author, alias_cols=False) where = query.build_where(Q(num__gt=2, name__isnull=False) | Q(num__lt=F("id"))) name_isnull_lookup, num_gt_lookup = where.children[0].children self.assertIsInstance(num_gt_lookup, GreaterThan) self.assertIsInstance(num_gt_lookup.lhs, Col) self.assertIsNone(num_gt_lookup.lhs.alias) self.assertIsInstance(name_isnull_lookup, IsNull) self.assertIsInstance(name_isnull_lookup.lhs, Col) self.assertIsNone(name_isnull_lookup.lhs.alias) num_lt_lookup = where.children[1] self.assertIsInstance(num_lt_lookup, LessThan) self.assertIsInstance(num_lt_lookup.rhs, Col) self.assertIsNone(num_lt_lookup.rhs.alias) self.assertIsInstance(num_lt_lookup.lhs, Col) self.assertIsNone(num_lt_lookup.lhs.alias)
def _get_index_expressions(self, model, schema_editor): if not self.expressions: return None index_expressions = [] for expression in self.expressions: index_expression = IndexExpression(expression) index_expression.set_wrapper_classes(schema_editor.connection) index_expressions.append(index_expression) return ExpressionList(*index_expressions).resolve_expression( Query(model, alias_cols=False), )
def test_PGCRYPT_KEY_setting_per_database_decrypt(self, db, model, vals): conn = connections['secondary'] obj = model(value=vals[0]) field = obj._meta.get_field('value') col = field.get_col(obj._meta.db_table) query = Query(model) compiler = SQLInsertCompiler(query, conn, 'secondary') sql, params = col.as_sql(compiler, conn) assert 'secondary_key' in sql
def _get_field(model, name): if django.VERSION[0] >= 1 and django.VERSION[1] >= 8: # Django 1.8+ - can use something like # expression.output_field.get_internal_field() == 'Money..' raise NotImplementedError("Django 1.8+ support is not implemented.") from django.db.models.fields import FieldDoesNotExist # Create a fake query object so we can easily work out what field # type we are dealing with qs = Query(model) opts = qs.get_meta() alias = qs.get_initial_alias() parts = name.split(LOOKUP_SEP) # The following is borrowed from the innards of Query.add_filter - it strips out __gt, __exact et al. num_parts = len(parts) if num_parts > 1 and parts[-1] in qs.query_terms: # Traverse the lookup query to distinguish related fields from # lookup types. lookup_model = model for counter, field_name in enumerate(parts): try: lookup_field = lookup_model._meta.get_field(field_name) except FieldDoesNotExist: # Not a field. Bail out. parts.pop() break # Unless we're at the end of the list of lookups, let's attempt # to continue traversing relations. if (counter + 1) < num_parts: try: lookup_model = lookup_field.rel.to except AttributeError: # Not a related field. Bail out. parts.pop() break if django.VERSION[0] >= 1 and django.VERSION[1] in (6, 7): # Django 1.6-1.7 field = qs.setup_joins(parts, opts, alias)[0] else: # Django 1.4-1.5 field = qs.setup_joins(parts, opts, alias, False)[0] return field
def test_foreign_key_f(self): query = Query(Ranking) with self.assertRaises(FieldError): query.build_where(Q(rank__gt=F('author__num')))
def get_related_where(self, fk_name, using, type): qn = self.get_quote_name(using) related_where = ["%s = %s.%s" % (qn(self.model._meta.pk.get_attname_column()[1]), type, qn(fk_name))] related_query = Query(self.manager.related.model) for name, value in self.filter.iteritems(): related_query.add_q(Q(**{name: value})) for name, value in self.exclude.iteritems(): related_query.add_q(~Q(**{name: value})) related_query.add_extra(None, None, ["%s = %s.%s" % (qn(self.model._meta.pk.get_attname_column()[1]), type, qn(self.manager.related.field.m2m_column_name()))], None, None, None) related_query.add_count_column() related_query.clear_ordering(force_empty=True) related_query.default_cols = False related_filter_where, related_where_params = related_query.get_compiler(using=using).as_sql() if related_filter_where is not None: related_where.append('(' + related_filter_where + ') > 0') return related_where, related_where_params
def test_foreign_key(self): query = Query(Item) msg = 'Joined field references are not permitted in this query' with self.assertRaisesMessage(FieldError, msg): query.build_where(Q(creator__num__gt=2))