diff --git a/django/db/models/query.py b/django/db/models/query.py index fea1144200..5c7d08fb39 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -796,7 +796,7 @@ class QuerySet(object): Returns the internal query's SQL and parameters (as a tuple). """ obj = self.values("pk") - if connection == connections[obj.db]: + if obj._db is None or connection == connections[obj._db]: return obj.query.get_compiler(connection=connection).as_nested_sql() raise ValueError("Can't do subqueries with queries on different DBs.") @@ -918,7 +918,7 @@ class ValuesQuerySet(QuerySet): % self.__class__.__name__) obj = self._clone() - if connection == connections[obj.db]: + if obj._db is None or connection == connections[obj._db]: return obj.query.get_compiler(connection=connection).as_nested_sql() raise ValueError("Can't do subqueries with queries on different DBs.") diff --git a/tests/regressiontests/multiple_database/tests.py b/tests/regressiontests/multiple_database/tests.py index 81b6a5ffb9..540648f0e8 100644 --- a/tests/regressiontests/multiple_database/tests.py +++ b/tests/regressiontests/multiple_database/tests.py @@ -655,6 +655,19 @@ class QueryTestCase(TestCase): # The editor instance should have a db state self.assertEqual(book.editor._state.db, 'other') + def test_subquery(self): + """Make sure as_sql works with subqueries and master/slave.""" + sub = Person.objects.using('other').filter(name='fff') + qs = Book.objects.filter(editor__in=sub) + + # When you call __str__ on the query object, it doesn't know about using + # so it falls back to the default. If the subquery explicitly uses a + # different database, an error should be raised. + self.assertRaises(ValueError, str, qs.query) + + # Evaluating the query shouldn't work, either + self.assertRaises(ValueError, list, qs) + class TestRouter(object): # A test router. The behaviour is vaguely master/slave, but the # databases aren't assumed to propagate changes. @@ -1137,6 +1150,26 @@ class RouterTestCase(TestCase): review3.content_object = dive self.assertEquals(review3._state.db, 'default') + def test_subquery(self): + """Make sure as_sql works with subqueries and master/slave.""" + # Create a book and author on the other database + + mark = Person.objects.using('other').create(name="Mark Pilgrim") + dive = Book.objects.using('other').create(title="Dive into Python", + published=datetime.date(2009, 5, 4), + editor=mark) + + sub = Person.objects.filter(name='Mark Pilgrim') + qs = Book.objects.filter(editor__in=sub) + + # When you call __str__ on the query object, it doesn't know about using + # so it falls back to the default. Don't let routing instructions + # force the subquery to an incompatible database. + str(qs.query) + + # If you evaluate the query, it should work, running on 'other' + self.assertEquals(list(qs.values_list('title', flat=True)), [u'Dive into Python']) + class AuthTestCase(TestCase): multi_db = True