From b002a032f90b8cd228cfcee6c88cd238a8191cc0 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Sat, 27 Jan 2018 11:12:11 +0100 Subject: [PATCH] Fixed #29054 -- Fixed a regression where a queryset that annotates with geometry objects crashes. Made GEOSGeometryBase hashable. Regression in 19b2dfd1bfe7fd716dd3d8bfa5f972070d83b42f. Thanks Tim Graham for the review. --- django/contrib/gis/geos/geometry.py | 3 +++ docs/releases/2.0.2.txt | 3 +++ tests/gis_tests/geoapp/test_expressions.py | 14 +++++++++++++- tests/gis_tests/geos_tests/test_geos.py | 16 ++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py index bcda25fa2f..1ebecc864b 100644 --- a/django/contrib/gis/geos/geometry.py +++ b/django/contrib/gis/geos/geometry.py @@ -144,6 +144,9 @@ class GEOSGeometryBase(GEOSBase): return False return isinstance(other, GEOSGeometry) and self.srid == other.srid and self.equals_exact(other) + def __hash__(self): + return hash((self.srid, self.wkt)) + # ### Geometry set-like operations ### # Thanks to Sean Gillies for inspiration: # http://lists.gispython.org/pipermail/community/2007-July/001034.html diff --git a/docs/releases/2.0.2.txt b/docs/releases/2.0.2.txt index 4a06ccb792..06968d4ba3 100644 --- a/docs/releases/2.0.2.txt +++ b/docs/releases/2.0.2.txt @@ -17,3 +17,6 @@ Bugfixes * Fixed regression in the use of ``QuerySet.values_list(..., flat=True)`` followed by ``annotate()`` (:ticket:`29067`). + +* Fixed a regression where a queryset that annotates with geometry objects + crashes (:ticket:`29054`). diff --git a/tests/gis_tests/geoapp/test_expressions.py b/tests/gis_tests/geoapp/test_expressions.py index 496e6b58ce..2d0ebbcae0 100644 --- a/tests/gis_tests/geoapp/test_expressions.py +++ b/tests/gis_tests/geoapp/test_expressions.py @@ -3,10 +3,11 @@ from unittest import skipUnless from django.contrib.gis.db.models import F, GeometryField, Value, functions from django.contrib.gis.geos import Point, Polygon from django.db import connection +from django.db.models import Count from django.test import TestCase, skipUnlessDBFeature from ..utils import postgis -from .models import City, ManyPointModel +from .models import City, ManyPointModel, MultiFields class GeoExpressionsTests(TestCase): @@ -48,6 +49,17 @@ class GeoExpressionsTests(TestCase): obj.refresh_from_db() self.assertTrue(obj.point3.equals_exact(p1.transform(3857, clone=True), 0.1)) + def test_multiple_annotation(self): + multi_field = MultiFields.objects.create( + point=Point(1, 1), + city=City.objects.get(name='Houston'), + poly=Polygon(((1, 1), (1, 2), (2, 2), (2, 1), (1, 1))), + ) + qs = City.objects.values('name').annotate( + distance=functions.Distance('multifields__point', multi_field.city.point), + ).annotate(count=Count('multifields')) + self.assertTrue(qs.first()) + @skipUnlessDBFeature('has_Translate_function') def test_update_with_expression(self): city = City.objects.create(point=Point(1, 1, srid=4326)) diff --git a/tests/gis_tests/geos_tests/test_geos.py b/tests/gis_tests/geos_tests/test_geos.py index db8c44d758..0c0197f8c1 100644 --- a/tests/gis_tests/geos_tests/test_geos.py +++ b/tests/gis_tests/geos_tests/test_geos.py @@ -187,6 +187,22 @@ class GEOSTest(SimpleTestCase, TestDataMixin): self.assertNotEqual(g, {'foo': 'bar'}) self.assertNotEqual(g, False) + def test_hash(self): + point_1 = Point(5, 23) + point_2 = Point(5, 23, srid=4326) + point_3 = Point(5, 23, srid=32632) + multipoint_1 = MultiPoint(point_1, srid=4326) + multipoint_2 = MultiPoint(point_2) + multipoint_3 = MultiPoint(point_3) + self.assertNotEqual(hash(point_1), hash(point_2)) + self.assertNotEqual(hash(point_1), hash(point_3)) + self.assertNotEqual(hash(point_2), hash(point_3)) + self.assertNotEqual(hash(multipoint_1), hash(multipoint_2)) + self.assertEqual(hash(multipoint_2), hash(multipoint_3)) + self.assertNotEqual(hash(multipoint_1), hash(point_1)) + self.assertNotEqual(hash(multipoint_2), hash(point_2)) + self.assertNotEqual(hash(multipoint_3), hash(point_3)) + def test_eq_with_srid(self): "Testing non-equivalence with different srids." p0 = Point(5, 23)