From 60d94c2a80a68861021526c0fef7fc40e648e81f Mon Sep 17 00:00:00 2001
From: Erik Romijn <eromijn@solidlinks.nl>
Date: Sun, 19 May 2013 13:28:09 +0200
Subject: [PATCH] Fixed #11442 -- Postgresql backend casts all inet types to
 text

---
 django/db/backends/__init__.py                       | 10 +++++-----
 django/db/backends/oracle/base.py                    |  2 +-
 django/db/backends/postgresql_psycopg2/operations.py |  4 ++--
 django/db/models/sql/where.py                        |  8 +++++---
 tests/string_lookup/tests.py                         |  4 +++-
 5 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 9acef4ad19..6eb111270e 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -765,12 +765,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'
 
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index 9e69743d33..6338ae09e7 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -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:
diff --git a/django/db/backends/postgresql_psycopg2/operations.py b/django/db/backends/postgresql_psycopg2/operations.py
index b17a0c17bb..f06eec5a1d 100644
--- a/django/db/backends/postgresql_psycopg2/operations.py
+++ b/django/db/backends/postgresql_psycopg2/operations.py
@@ -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'
 
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index 029226383d..ff3d1bdcfb 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -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)
@@ -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)
@@ -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
@@ -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):
         """
diff --git a/tests/string_lookup/tests.py b/tests/string_lookup/tests.py
index 02f766adce..b011720ddf 100644
--- a/tests/string_lookup/tests.py
+++ b/tests/string_lookup/tests.py
@@ -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