diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index aa0191b068..855b6fdec1 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -1267,6 +1267,14 @@ class BaseDatabaseIntrospection(object): """ return name + def column_name_converter(self, name): + """ + Apply a conversion to the column name for the purposes of comparison. + + Uses table_name_converter() by default. + """ + return self.table_name_converter(name) + def table_names(self, cursor=None): """ Returns a list of names of all tables that exist in the database. diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py index f029715cf2..0d7c36a40c 100644 --- a/django/db/backends/sqlite3/introspection.py +++ b/django/db/backends/sqlite3/introspection.py @@ -68,6 +68,21 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): return [FieldInfo(info['name'], info['type'], None, info['size'], None, None, info['null_ok']) for info in self._table_info(cursor, table_name)] + def column_name_converter(self, name): + """ + SQLite will in some cases, e.g. when returning columns from views and + subselects, return column names in 'alias."column"' format instead of + simply 'column'. + + Affects SQLite < 3.7.15, fixed by http://www.sqlite.org/src/info/5526e0aa3c + """ + # TODO: remove when SQLite < 3.7.15 is sufficiently old. + # 3.7.13 ships in Debian stable as of 2014-03-21. + if self.connection.Database.sqlite_version_info < (3, 7, 15): + return name.split('.')[-1].strip('"') + else: + return name + def get_relations(self, cursor, table_name): """ Returns a dictionary of {field_index: (field_index_other_table, other_table)} diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index c03d782440..89fba2b56a 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -66,7 +66,7 @@ class RawQuery(object): def get_columns(self): if self.cursor is None: self._execute_query() - converter = connections[self.using].introspection.table_name_converter + converter = connections[self.using].introspection.column_name_converter return [converter(column_meta[0]) for column_meta in self.cursor.description] diff --git a/tests/raw_query/tests.py b/tests/raw_query/tests.py index 80372c1ae0..7d81ee8ded 100644 --- a/tests/raw_query/tests.py +++ b/tests/raw_query/tests.py @@ -239,3 +239,9 @@ class RawQueryTests(TestCase): def test_query_count(self): self.assertNumQueries(1, list, Author.objects.raw("SELECT * FROM raw_query_author")) + + def test_subquery_in_raw_sql(self): + try: + list(Book.objects.raw('SELECT "id" FROM (SELECT * FROM raw_query_book WHERE paperback) sq')) + except InvalidQuery: + self.fail("Using a subquery in a RawQuerySet raised InvalidQuery")