Commit a0b5f15e authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #14483 -- Allowed using subqueries with GIS lookups

parent 293fd5da
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -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."
+3 −0
Original line number Diff line number Diff line
@@ -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):
+15 −0
Original line number Diff line number Diff line
@@ -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())
+1 −1
Original line number Diff line number Diff line
@@ -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):
        """
+3 −0
Original line number Diff line number Diff line
@@ -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.