From ef3ae3d1c94ac1d4ffaeeeec1ee544e91431e65b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Vlastimil=20Z=C3=ADma?= <vlastimil.zima@nic.cz>
Date: Mon, 19 May 2014 18:19:35 +0200
Subject: [PATCH] [1.6.x] Fixed #22514 -- Prevented indexes on virtual fields
 [postgres].

Backport of 78c32f1caa from master
---
 .../backends/postgresql_psycopg2/creation.py  |  4 +--
 docs/releases/1.6.6.txt                       |  3 +++
 tests/indexes/models.py                       | 25 +++++++++++++++++++
 tests/indexes/tests.py                        |  9 ++++++-
 4 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/django/db/backends/postgresql_psycopg2/creation.py b/django/db/backends/postgresql_psycopg2/creation.py
index d4260e05c4..6ed1c451f1 100644
--- a/django/db/backends/postgresql_psycopg2/creation.py
+++ b/django/db/backends/postgresql_psycopg2/creation.py
@@ -41,7 +41,8 @@ class DatabaseCreation(BaseDatabaseCreation):
 
     def sql_indexes_for_field(self, model, f, style):
         output = []
-        if f.db_index or f.unique:
+        db_type = f.db_type(connection=self.connection)
+        if db_type is not None and (f.db_index or f.unique):
             qn = self.connection.ops.quote_name
             db_table = model._meta.db_table
             tablespace = f.db_tablespace or model._meta.db_tablespace
@@ -67,7 +68,6 @@ class DatabaseCreation(BaseDatabaseCreation):
             # a second index that specifies their operator class, which is
             # needed when performing correct LIKE queries outside the
             # C locale. See #12234.
-            db_type = f.db_type(connection=self.connection)
             if db_type.startswith('varchar'):
                 output.append(get_index_sql('%s_%s_like' % (db_table, f.column),
                                             ' varchar_pattern_ops'))
diff --git a/docs/releases/1.6.6.txt b/docs/releases/1.6.6.txt
index 9084f81ee1..103af36c37 100644
--- a/docs/releases/1.6.6.txt
+++ b/docs/releases/1.6.6.txt
@@ -11,3 +11,6 @@ Bugfixes
 
 * Corrected email and URL validation to reject a trailing dash
   (`#22579 <http://code.djangoproject.com/ticket/22579>`_).
+
+* Prevented indexes on PostgreSQL virtual fields
+  (`#22514 <http://code.djangoproject.com/ticket/22514>`_).
diff --git a/tests/indexes/models.py b/tests/indexes/models.py
index e38eb005db..bdc75c2db7 100644
--- a/tests/indexes/models.py
+++ b/tests/indexes/models.py
@@ -2,10 +2,35 @@ from django.db import connection
 from django.db import models
 
 
+class CurrentTranslation(models.ForeignObject):
+    """
+    Creates virtual relation to the translation with model cache enabled.
+    """
+    # Avoid validation
+    requires_unique_target = False
+
+    def __init__(self, to, from_fields, to_fields, **kwargs):
+        # Disable reverse relation
+        kwargs['related_name'] = '+'
+        # Set unique to enable model cache.
+        kwargs['unique'] = True
+        super(CurrentTranslation, self).__init__(to, from_fields, to_fields, **kwargs)
+
+
+class ArticleTranslation(models.Model):
+
+    article = models.ForeignKey('indexes.Article')
+    language = models.CharField(max_length=10, unique=True)
+    content = models.TextField()
+
+
 class Article(models.Model):
     headline = models.CharField(max_length=100)
     pub_date = models.DateTimeField()
 
+    # Add virtual relation to the ArticleTranslation model.
+    translation = CurrentTranslation(ArticleTranslation, ['id'], ['article'])
+
     class Meta:
         index_together = [
             ["headline", "pub_date"],
diff --git a/tests/indexes/tests.py b/tests/indexes/tests.py
index 672e35d286..694696b342 100644
--- a/tests/indexes/tests.py
+++ b/tests/indexes/tests.py
@@ -1,5 +1,5 @@
 from django.core.management.color import no_style
-from django.db import connections, DEFAULT_DB_ALIAS
+from django.db import connection, connections, DEFAULT_DB_ALIAS
 from django.test import TestCase
 from django.utils.unittest import skipUnless
 
@@ -25,3 +25,10 @@ class IndexesTests(TestCase):
         # unique=True and db_index=True should only create the varchar-specific
         # index (#19441).
         self.assertIn('("slug" varchar_pattern_ops)', index_sql[4])
+
+    @skipUnless(connection.vendor == 'postgresql',
+        "This is a postgresql-specific issue")
+    def test_postgresql_virtual_relation_indexes(self):
+        """Test indexes are not created for related objects"""
+        index_sql = connection.creation.sql_indexes_for_model(Article, no_style())
+        self.assertEqual(len(index_sql), 1)