mirror of https://github.com/django/django.git
Fixed #14483 -- Allowed using subqueries with GIS lookups
This commit is contained in:
parent
293fd5da5b
commit
a0b5f15ea5
|
@ -293,10 +293,11 @@ class GeometryField(GeoSelectFormatMixin, Field):
|
||||||
(lookup_type, self.__class__.__name__))
|
(lookup_type, self.__class__.__name__))
|
||||||
|
|
||||||
def get_prep_lookup(self, lookup_type, value):
|
def get_prep_lookup(self, lookup_type, value):
|
||||||
if lookup_type == 'isnull':
|
if lookup_type == 'contains':
|
||||||
return bool(value)
|
# 'contains' name might conflict with the "normal" contains lookup,
|
||||||
else:
|
# for which the value is not prepared, but left as-is.
|
||||||
return self.get_prep_value(value)
|
return self.get_prep_value(value)
|
||||||
|
return super(GeometryField, self).get_prep_lookup(lookup_type, value)
|
||||||
|
|
||||||
def get_db_prep_save(self, value, connection):
|
def get_db_prep_save(self, value, connection):
|
||||||
"Prepares the value for saving in the database."
|
"Prepares the value for saving in the database."
|
||||||
|
|
|
@ -66,6 +66,9 @@ class GISLookup(Lookup):
|
||||||
|
|
||||||
def process_rhs(self, compiler, connection):
|
def process_rhs(self, compiler, connection):
|
||||||
rhs, rhs_params = super(GISLookup, self).process_rhs(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
|
geom = self.rhs
|
||||||
if isinstance(self.rhs, Col):
|
if isinstance(self.rhs, Col):
|
||||||
|
|
|
@ -890,6 +890,21 @@ class GeoQuerySetTest(TestCase):
|
||||||
self.assertIsNone(qs.unionagg(field_name='point'))
|
self.assertIsNone(qs.unionagg(field_name='point'))
|
||||||
self.assertIsNone(qs.aggregate(Union('point'))['point__union'])
|
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):
|
def test_non_concrete_field(self):
|
||||||
NonConcreteModel.objects.create(point=Point(0, 0), name='name')
|
NonConcreteModel.objects.create(point=Point(0, 0), name='name')
|
||||||
list(NonConcreteModel.objects.all())
|
list(NonConcreteModel.objects.all())
|
||||||
|
|
|
@ -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 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
|
# If there is no slicing in use, then we can safely drop all ordering
|
||||||
obj.clear_ordering(True)
|
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):
|
def get_default_columns(self, start_alias=None, opts=None, from_parent=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -216,6 +216,9 @@ Minor features
|
||||||
* A new :doc:`GeoJSON serializer </ref/contrib/gis/serializers>` is now
|
* A new :doc:`GeoJSON serializer </ref/contrib/gis/serializers>` is now
|
||||||
available.
|
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
|
* The Spatialite backend now supports ``Collect`` and ``Extent`` aggregates
|
||||||
when the database version is 3.0 or later.
|
when the database version is 3.0 or later.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue