Loading django/db/backends/__init__.py +5 −5 Original line number Diff line number Diff line Loading @@ -766,12 +766,12 @@ class BaseDatabaseOperations(object): """ return cursor.fetchone()[0] def field_cast_sql(self, db_type): def field_cast_sql(self, db_type, internal_type): """ Given a column type (e.g. 'BLOB', 'VARCHAR'), returns the SQL necessary to cast it before using it in a WHERE statement. Note that the resulting string should contain a '%s' placeholder for the column being searched against. Given a column type (e.g. 'BLOB', 'VARCHAR'), and an internal type (e.g. 'GenericIPAddressField'), returns the SQL necessary to cast it before using it in a WHERE statement. Note that the resulting string should contain a '%s' placeholder for the column being searched against. """ return '%s' Loading django/db/backends/oracle/base.py +1 −1 Original line number Diff line number Diff line Loading @@ -254,7 +254,7 @@ WHEN (new.%(col_name)s IS NULL) def fetch_returned_insert_id(self, cursor): return int(cursor._insert_id_var.getvalue()) def field_cast_sql(self, db_type): def field_cast_sql(self, db_type, internal_type): if db_type and db_type.endswith('LOB'): return "DBMS_LOB.SUBSTR(%s)" else: Loading django/db/backends/postgresql_psycopg2/operations.py +2 −2 Original line number Diff line number Diff line Loading @@ -78,8 +78,8 @@ class DatabaseOperations(BaseDatabaseOperations): return lookup def field_cast_sql(self, db_type): if db_type == 'inet': def field_cast_sql(self, db_type, internal_type): if internal_type == "GenericIPAddressField" or internal_type == "IPAddressField": return 'HOST(%s)' return '%s' Loading django/db/models/sql/where.py +5 −3 Original line number Diff line number Diff line Loading @@ -174,6 +174,8 @@ class WhereNode(tree.Node): it. """ lvalue, lookup_type, value_annotation, params_or_value = child field_internal_type = lvalue.field.get_internal_type() if lvalue.field else None if isinstance(lvalue, Constraint): try: lvalue, params = lvalue.process(lookup_type, params_or_value, connection) Loading @@ -187,7 +189,7 @@ class WhereNode(tree.Node): if isinstance(lvalue, tuple): # A direct database column lookup. field_sql, field_params = self.sql_for_columns(lvalue, qn, connection), [] field_sql, field_params = self.sql_for_columns(lvalue, qn, connection, field_internal_type), [] else: # A smart object with an as_sql() method. field_sql, field_params = lvalue.as_sql(qn, connection) Loading Loading @@ -257,7 +259,7 @@ class WhereNode(tree.Node): raise TypeError('Invalid lookup_type: %r' % lookup_type) def sql_for_columns(self, data, qn, connection): def sql_for_columns(self, data, qn, connection, internal_type=None): """ Returns the SQL fragment used for the left-hand side of a column constraint (for example, the "T1.foo" portion in the clause Loading @@ -268,7 +270,7 @@ class WhereNode(tree.Node): lhs = '%s.%s' % (qn(table_alias), qn(name)) else: lhs = qn(name) return connection.ops.field_cast_sql(db_type) % lhs return connection.ops.field_cast_sql(db_type, internal_type) % lhs def relabel_aliases(self, change_map): """ Loading tests/string_lookup/tests.py +3 −1 Original line number Diff line number Diff line Loading @@ -73,9 +73,11 @@ class StringLookupTests(TestCase): """ Regression test for #708 "like" queries on IP address fields require casting to text (on PostgreSQL). "like" queries on IP address fields require casting with HOST() (on PostgreSQL). """ a = Article(name='IP test', text='The body', submitted_from='192.0.2.100') a.save() self.assertEqual(repr(Article.objects.filter(submitted_from__contains='192.0.2')), repr([a])) # Test that the searches do not match the subnet mask (/32 in this case) self.assertEqual(Article.objects.filter(submitted_from__contains='32').count(), 0) No newline at end of file Loading
django/db/backends/__init__.py +5 −5 Original line number Diff line number Diff line Loading @@ -766,12 +766,12 @@ class BaseDatabaseOperations(object): """ return cursor.fetchone()[0] def field_cast_sql(self, db_type): def field_cast_sql(self, db_type, internal_type): """ Given a column type (e.g. 'BLOB', 'VARCHAR'), returns the SQL necessary to cast it before using it in a WHERE statement. Note that the resulting string should contain a '%s' placeholder for the column being searched against. Given a column type (e.g. 'BLOB', 'VARCHAR'), and an internal type (e.g. 'GenericIPAddressField'), returns the SQL necessary to cast it before using it in a WHERE statement. Note that the resulting string should contain a '%s' placeholder for the column being searched against. """ return '%s' Loading
django/db/backends/oracle/base.py +1 −1 Original line number Diff line number Diff line Loading @@ -254,7 +254,7 @@ WHEN (new.%(col_name)s IS NULL) def fetch_returned_insert_id(self, cursor): return int(cursor._insert_id_var.getvalue()) def field_cast_sql(self, db_type): def field_cast_sql(self, db_type, internal_type): if db_type and db_type.endswith('LOB'): return "DBMS_LOB.SUBSTR(%s)" else: Loading
django/db/backends/postgresql_psycopg2/operations.py +2 −2 Original line number Diff line number Diff line Loading @@ -78,8 +78,8 @@ class DatabaseOperations(BaseDatabaseOperations): return lookup def field_cast_sql(self, db_type): if db_type == 'inet': def field_cast_sql(self, db_type, internal_type): if internal_type == "GenericIPAddressField" or internal_type == "IPAddressField": return 'HOST(%s)' return '%s' Loading
django/db/models/sql/where.py +5 −3 Original line number Diff line number Diff line Loading @@ -174,6 +174,8 @@ class WhereNode(tree.Node): it. """ lvalue, lookup_type, value_annotation, params_or_value = child field_internal_type = lvalue.field.get_internal_type() if lvalue.field else None if isinstance(lvalue, Constraint): try: lvalue, params = lvalue.process(lookup_type, params_or_value, connection) Loading @@ -187,7 +189,7 @@ class WhereNode(tree.Node): if isinstance(lvalue, tuple): # A direct database column lookup. field_sql, field_params = self.sql_for_columns(lvalue, qn, connection), [] field_sql, field_params = self.sql_for_columns(lvalue, qn, connection, field_internal_type), [] else: # A smart object with an as_sql() method. field_sql, field_params = lvalue.as_sql(qn, connection) Loading Loading @@ -257,7 +259,7 @@ class WhereNode(tree.Node): raise TypeError('Invalid lookup_type: %r' % lookup_type) def sql_for_columns(self, data, qn, connection): def sql_for_columns(self, data, qn, connection, internal_type=None): """ Returns the SQL fragment used for the left-hand side of a column constraint (for example, the "T1.foo" portion in the clause Loading @@ -268,7 +270,7 @@ class WhereNode(tree.Node): lhs = '%s.%s' % (qn(table_alias), qn(name)) else: lhs = qn(name) return connection.ops.field_cast_sql(db_type) % lhs return connection.ops.field_cast_sql(db_type, internal_type) % lhs def relabel_aliases(self, change_map): """ Loading
tests/string_lookup/tests.py +3 −1 Original line number Diff line number Diff line Loading @@ -73,9 +73,11 @@ class StringLookupTests(TestCase): """ Regression test for #708 "like" queries on IP address fields require casting to text (on PostgreSQL). "like" queries on IP address fields require casting with HOST() (on PostgreSQL). """ a = Article(name='IP test', text='The body', submitted_from='192.0.2.100') a.save() self.assertEqual(repr(Article.objects.filter(submitted_from__contains='192.0.2')), repr([a])) # Test that the searches do not match the subnet mask (/32 in this case) self.assertEqual(Article.objects.filter(submitted_from__contains='32').count(), 0) No newline at end of file