summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2015-01-17 00:17:54 +0100
committerClaude Paroz <claude@2xlibre.net>2015-01-30 20:27:18 +0100
commita0b5f15ea5f1abd91da9a5e4e5b6a0fb5a880c43 (patch)
treeab860a2f14d200b6d0e0cccc50af69e2a276e88a
parent293fd5da5b8c7b79bd34ef793ab45c1bb8ac69ea (diff)
Fixed #14483 -- Allowed using subqueries with GIS lookups
-rw-r--r--django/contrib/gis/db/models/fields.py7
-rw-r--r--django/contrib/gis/db/models/lookups.py3
-rw-r--r--django/contrib/gis/tests/geoapp/tests.py15
-rw-r--r--django/db/models/sql/compiler.py2
-rw-r--r--docs/releases/1.8.txt3
5 files changed, 26 insertions, 4 deletions
diff --git a/django/contrib/gis/db/models/fields.py b/django/contrib/gis/db/models/fields.py
index 927118c0ac..5e70697a2b 100644
--- a/django/contrib/gis/db/models/fields.py
+++ b/django/contrib/gis/db/models/fields.py
@@ -293,10 +293,11 @@ class GeometryField(GeoSelectFormatMixin, Field):
(lookup_type, self.__class__.__name__))
def get_prep_lookup(self, lookup_type, value):
- if lookup_type == 'isnull':
- return bool(value)
- else:
+ if lookup_type == 'contains':
+ # 'contains' name might conflict with the "normal" contains lookup,
+ # for which the value is not prepared, but left as-is.
return self.get_prep_value(value)
+ return super(GeometryField, self).get_prep_lookup(lookup_type, value)
def get_db_prep_save(self, value, connection):
"Prepares the value for saving in the database."
diff --git a/django/contrib/gis/db/models/lookups.py b/django/contrib/gis/db/models/lookups.py
index 17ed1a95c8..eb64eff6c7 100644
--- a/django/contrib/gis/db/models/lookups.py
+++ b/django/contrib/gis/db/models/lookups.py
@@ -66,6 +66,9 @@ class GISLookup(Lookup):
def process_rhs(self, compiler, connection):
rhs, rhs_params = super(GISLookup, self).process_rhs(compiler, connection)
+ if hasattr(self.rhs, '_as_sql'):
+ # If rhs is some QuerySet, don't touch it
+ return rhs, rhs_params
geom = self.rhs
if isinstance(self.rhs, Col):
diff --git a/django/contrib/gis/tests/geoapp/tests.py b/django/contrib/gis/tests/geoapp/tests.py
index 8a885b2827..7c999a20d0 100644
--- a/django/contrib/gis/tests/geoapp/tests.py
+++ b/django/contrib/gis/tests/geoapp/tests.py
@@ -890,6 +890,21 @@ class GeoQuerySetTest(TestCase):
self.assertIsNone(qs.unionagg(field_name='point'))
self.assertIsNone(qs.aggregate(Union('point'))['point__union'])
+ def test_within_subquery(self):
+ """
+ Test that using a queryset inside a geo lookup is working (using a subquery)
+ (#14483).
+ """
+ tex_cities = City.objects.filter(
+ point__within=Country.objects.filter(name='Texas').values('mpoly')).order_by('name')
+ expected = ['Dallas', 'Houston']
+ if not connection.features.supports_real_shape_operations:
+ expected.append('Oklahoma City')
+ self.assertEqual(
+ list(tex_cities.values_list('name', flat=True)),
+ expected
+ )
+
def test_non_concrete_field(self):
NonConcreteModel.objects.create(point=Point(0, 0), name='name')
list(NonConcreteModel.objects.all())
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 5b647888d1..8f3af37031 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -466,7 +466,7 @@ class SQLCompiler(object):
if obj.low_mark == 0 and obj.high_mark is None and not self.query.distinct_fields:
# If there is no slicing in use, then we can safely drop all ordering
obj.clear_ordering(True)
- return obj.get_compiler(connection=self.connection).as_sql()
+ return obj.get_compiler(connection=self.connection).as_sql(subquery=True)
def get_default_columns(self, start_alias=None, opts=None, from_parent=None):
"""
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index a283e3c157..1743d6e6ce 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -216,6 +216,9 @@ Minor features
* A new :doc:`GeoJSON serializer </ref/contrib/gis/serializers>` is now
available.
+* It is now allowed to include a subquery as a geographic lookup argument, for
+ example ``City.objects.filter(point__within=Country.objects.filter(continent='Africa').values('mpoly'))``.
+
* The Spatialite backend now supports ``Collect`` and ``Extent`` aggregates
when the database version is 3.0 or later.