From 60d94c2a80a68861021526c0fef7fc40e648e81f Mon Sep 17 00:00:00 2001 From: Erik Romijn Date: Sun, 19 May 2013 13:28:09 +0200 Subject: Fixed #11442 -- Postgresql backend casts all inet types to text --- django/db/models/sql/where.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'django/db/models/sql/where.py') 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): """ -- cgit v1.3 From f53059b41148da77e8c4cdfcdbec3a7514cd97c9 Mon Sep 17 00:00:00 2001 From: Anssi Kääriäinen Date: Mon, 20 May 2013 14:24:48 +0300 Subject: Fixed qs.values() regression when used in subquery --- django/db/models/sql/where.py | 7 ++++++- tests/queries/tests.py | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'django/db/models/sql/where.py') diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py index ff3d1bdcfb..08f9d6c837 100644 --- a/django/db/models/sql/where.py +++ b/django/db/models/sql/where.py @@ -399,7 +399,12 @@ class SubqueryConstraint(object): if hasattr(query, 'values'): if query._db and connection.alias != query._db: raise ValueError("Can't do subqueries with queries on different DBs.") - query = query.values(*self.targets).query + # Do not override already existing values. + if not hasattr(query, 'field_names'): + query = query.values(*self.targets) + else: + query = query._clone() + query = query.query query.clear_ordering(True) query_compiler = query.get_compiler(connection=connection) diff --git a/tests/queries/tests.py b/tests/queries/tests.py index cdc26248c9..ad5dde34b5 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -2831,3 +2831,20 @@ class EmptyStringPromotionTests(TestCase): self.assertIn('LEFT OUTER JOIN', str(qs.query)) else: self.assertNotIn('LEFT OUTER JOIN', str(qs.query)) + +class ValuesSubqueryTests(TestCase): + def test_values_in_subquery(self): + # Check that if a values() queryset is used, then the given values + # will be used instead of forcing use of the relation's field. + o1 = Order.objects.create(id=-2) + o2 = Order.objects.create(id=-1) + oi1 = OrderItem.objects.create(order=o1, status=0) + oi1.status = oi1.pk + oi1.save() + OrderItem.objects.create(order=o2, status=0) + + # The query below should match o1 as it has related order_item + # with id == status. + self.assertQuerysetEqual( + Order.objects.filter(items__in=OrderItem.objects.values_list('status')), + [o1.pk], lambda x: x.pk) -- cgit v1.3 From d467e117856a7fa6da5e90471144aaa82d822065 Mon Sep 17 00:00:00 2001 From: Anssi Kääriäinen Date: Mon, 27 May 2013 11:29:43 +0300 Subject: Fixed #20507 -- SubqueryConstraint alias relabeling The SubqueryConstraint defined relabeled_clone(), but that was never called. Instead there is now clone() and relabel_aliases() methods for SubqueryConstraint. A related problem was that SubqueryConstraint didn't correctly use quote_name_unless_alias() of the outer query. This resulted in failures when running under PostgreSQL. --- django/db/models/sql/compiler.py | 3 +-- django/db/models/sql/where.py | 11 +++++++---- tests/queries/tests.py | 16 +++++++++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) (limited to 'django/db/models/sql/where.py') diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index bbe310c8c3..0180f6b6cc 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -786,8 +786,7 @@ class SQLCompiler(object): return list(result) return result - def as_subquery_condition(self, alias, columns): - qn = self.quote_name_unless_alias + def as_subquery_condition(self, alias, columns, qn): qn2 = self.connection.ops.quote_name if len(columns) == 1: sql, params = self.as_sql() diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py index 08f9d6c837..2a342d417a 100644 --- a/django/db/models/sql/where.py +++ b/django/db/models/sql/where.py @@ -408,9 +408,12 @@ class SubqueryConstraint(object): query.clear_ordering(True) query_compiler = query.get_compiler(connection=connection) - return query_compiler.as_subquery_condition(self.alias, self.columns) + return query_compiler.as_subquery_condition(self.alias, self.columns, qn) - def relabeled_clone(self, relabels): + def relabel_aliases(self, change_map): + self.alias = change_map.get(self.alias, self.alias) + + def clone(self): return self.__class__( - relabels.get(self.alias, self.alias), - self.columns, self.query_object) + self.alias, self.columns, self.targets, + self.query_object) diff --git a/tests/queries/tests.py b/tests/queries/tests.py index 68a06abb49..2d6fc0b008 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -17,7 +17,7 @@ from django.utils import unittest from django.utils.datastructures import SortedDict from .models import (Annotation, Article, Author, Celebrity, Child, Cover, - Detail, DumbCategory, ExtraInfo, Fan, Item, LeafA, LoopX, LoopZ, + Detail, DumbCategory, ExtraInfo, Fan, Item, LeafA, Join, LeafB, LoopX, LoopZ, ManagedModel, Member, NamedCategory, Note, Number, Plaything, PointerA, Ranking, Related, Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten, Node, ObjectA, ObjectB, ObjectC, CategoryItem, SimpleCategory, @@ -2827,3 +2827,17 @@ class ValuesSubqueryTests(TestCase): self.assertQuerysetEqual( Order.objects.filter(items__in=OrderItem.objects.values_list('status')), [o1.pk], lambda x: x.pk) + +class DoubleInSubqueryTests(TestCase): + def test_double_subquery_in(self): + lfa1 = LeafA.objects.create(data='foo') + lfa2 = LeafA.objects.create(data='bar') + lfb1 = LeafB.objects.create(data='lfb1') + lfb2 = LeafB.objects.create(data='lfb2') + Join.objects.create(a=lfa1, b=lfb1) + Join.objects.create(a=lfa2, b=lfb2) + leaf_as = LeafA.objects.filter(data='foo').values_list('pk', flat=True) + joins = Join.objects.filter(a__in=leaf_as).values_list('b__id', flat=True) + qs = LeafB.objects.filter(pk__in=joins) + self.assertQuerysetEqual( + qs, [lfb1], lambda x: x) -- cgit v1.3