Browse Source

Refs #24152 -- Removed deprecated GeoQuerySet aggregate methods.

Per deprecation timeline.
Tim Graham 9 years ago
parent
commit
5d383549ee

+ 1 - 97
django/contrib/gis/db/models/query.py

@@ -1,6 +1,5 @@
 import warnings
 
-from django.contrib.gis.db.models import aggregates
 from django.contrib.gis.db.models.fields import (
     GeometryField, LineStringField, PointField, get_srid_info,
 )
@@ -15,9 +14,7 @@ from django.db.models.expressions import RawSQL
 from django.db.models.fields import Field
 from django.db.models.query import QuerySet
 from django.utils import six
-from django.utils.deprecation import (
-    RemovedInDjango20Warning, RemovedInDjango110Warning,
-)
+from django.utils.deprecation import RemovedInDjango20Warning
 
 
 class GeoQuerySet(QuerySet):
@@ -62,19 +59,6 @@ class GeoQuerySet(QuerySet):
         """
         return self._geom_attribute('centroid', **kwargs)
 
-    def collect(self, **kwargs):
-        """
-        Performs an aggregate collect operation on the given geometry field.
-        This is analogous to a union operation, but much faster because
-        boundaries are not dissolved.
-        """
-        warnings.warn(
-            "The collect GeoQuerySet method is deprecated. Use the Collect() "
-            "aggregate in an aggregate() or annotate() method.",
-            RemovedInDjango110Warning, stacklevel=2
-        )
-        return self._spatial_aggregate(aggregates.Collect, **kwargs)
-
     def difference(self, geom, **kwargs):
         """
         Returns the spatial difference of the geographic field in a `difference`
@@ -108,31 +92,6 @@ class GeoQuerySet(QuerySet):
         """
         return self._geom_attribute('envelope', **kwargs)
 
-    def extent(self, **kwargs):
-        """
-        Returns the extent (aggregate) of the features in the GeoQuerySet.  The
-        extent will be returned as a 4-tuple, consisting of (xmin, ymin, xmax, ymax).
-        """
-        warnings.warn(
-            "The extent GeoQuerySet method is deprecated. Use the Extent() "
-            "aggregate in an aggregate() or annotate() method.",
-            RemovedInDjango110Warning, stacklevel=2
-        )
-        return self._spatial_aggregate(aggregates.Extent, **kwargs)
-
-    def extent3d(self, **kwargs):
-        """
-        Returns the aggregate extent, in 3D, of the features in the
-        GeoQuerySet. It is returned as a 6-tuple, comprising:
-          (xmin, ymin, zmin, xmax, ymax, zmax).
-        """
-        warnings.warn(
-            "The extent3d GeoQuerySet method is deprecated. Use the Extent3D() "
-            "aggregate in an aggregate() or annotate() method.",
-            RemovedInDjango110Warning, stacklevel=2
-        )
-        return self._spatial_aggregate(aggregates.Extent3D, **kwargs)
-
     def force_rhr(self, **kwargs):
         """
         Returns a modified version of the Polygon/MultiPolygon in which
@@ -227,19 +186,6 @@ class GeoQuerySet(QuerySet):
         """
         return self._distance_attribute('length', None, **kwargs)
 
-    def make_line(self, **kwargs):
-        """
-        Creates a linestring from all of the PointField geometries in the
-        this GeoQuerySet and returns it.  This is a spatial aggregate
-        method, and thus returns a geometry rather than a GeoQuerySet.
-        """
-        warnings.warn(
-            "The make_line GeoQuerySet method is deprecated. Use the MakeLine() "
-            "aggregate in an aggregate() or annotate() method.",
-            RemovedInDjango110Warning, stacklevel=2
-        )
-        return self._spatial_aggregate(aggregates.MakeLine, geo_field_type=PointField, **kwargs)
-
     def mem_size(self, **kwargs):
         """
         Returns the memory size (number of bytes) that the geometry field takes
@@ -415,19 +361,6 @@ class GeoQuerySet(QuerySet):
         """
         return self._geomset_attribute('union', geom, **kwargs)
 
-    def unionagg(self, **kwargs):
-        """
-        Performs an aggregate union on the given geometry field.  Returns
-        None if the GeoQuerySet is empty.  The `tolerance` keyword is for
-        Oracle backends only.
-        """
-        warnings.warn(
-            "The unionagg GeoQuerySet method is deprecated. Use the Union() "
-            "aggregate in an aggregate() or annotate() method.",
-            RemovedInDjango110Warning, stacklevel=2
-        )
-        return self._spatial_aggregate(aggregates.Union, **kwargs)
-
     # ### Private API -- Abstracted DRY routines. ###
     def _spatial_setup(self, att, desc=None, field_name=None, geo_field_type=None):
         """
@@ -462,35 +395,6 @@ class GeoQuerySet(QuerySet):
 
         return procedure_args, geo_field
 
-    def _spatial_aggregate(self, aggregate, field_name=None,
-                           geo_field_type=None, tolerance=0.05):
-        """
-        DRY routine for calling aggregate spatial stored procedures and
-        returning their result to the caller of the function.
-        """
-        # Getting the field the geographic aggregate will be called on.
-        geo_field = self._geo_field(field_name)
-        if not geo_field:
-            raise TypeError('%s aggregate only available on GeometryFields.' % aggregate.name)
-
-        # Checking if there are any geo field type limitations on this
-        # aggregate (e.g. ST_Makeline only operates on PointFields).
-        if geo_field_type is not None and not isinstance(geo_field, geo_field_type):
-            raise TypeError('%s aggregate may only be called on %ss.' % (aggregate.name, geo_field_type.__name__))
-
-        # Getting the string expression of the field name, as this is the
-        # argument taken by `Aggregate` objects.
-        agg_col = field_name or geo_field.name
-
-        # Adding any keyword parameters for the Aggregate object. Oracle backends
-        # in particular need an additional `tolerance` parameter.
-        agg_kwargs = {}
-        if connections[self.db].ops.oracle:
-            agg_kwargs['tolerance'] = tolerance
-
-        # Calling the QuerySet.aggregate, and returning only the value of the aggregate.
-        return self.aggregate(geoagg=aggregate(agg_col, **agg_kwargs))['geoagg']
-
     def _spatial_attribute(self, att, settings, field_name=None, model_att=None):
         """
         DRY routine for calling a spatial stored procedure on a geometry column

+ 0 - 66
docs/ref/contrib/gis/geoquerysets.txt

@@ -1216,72 +1216,6 @@ Returns the number of points in the first linestring in the
 geometry field in a ``num_points`` attribute on each element of
 the ``GeoQuerySet``; otherwise sets with ``None``.
 
-Spatial Aggregates
-==================
-
-Aggregate Methods
------------------
-
-.. deprecated:: 1.8
-
-    Aggregate methods are now deprecated. Prefer using their function-based
-    equivalents.
-
-``collect``
-~~~~~~~~~~~
-
-.. method:: GeoQuerySet.collect(**kwargs)
-
-.. deprecated:: 1.8
-
-    Use the :class:`Collect` aggregate instead.
-
-Shortcut for ``aggregate(Collect(<field>))``.
-
-``extent``
-~~~~~~~~~~
-
-.. method:: GeoQuerySet.extent(**kwargs)
-
-.. deprecated:: 1.8
-
-    Use the :class:`Extent` aggregate instead.
-
-Shortcut for ``aggregate(Extent(<field>))``.
-
-``extent3d``
-~~~~~~~~~~~~
-
-.. method:: GeoQuerySet.extent3d(**kwargs)
-
-.. deprecated:: 1.8
-
-    Use the :class:`Extent` aggregate instead.
-
-Shortcut for ``aggregate(Extent3D(<field>))``.
-
-``make_line``
-~~~~~~~~~~~~~
-
-.. method:: GeoQuerySet.make_line(**kwargs)
-
-.. deprecated:: 1.8
-
-    Use the :class:`MakeLine` aggregate instead.
-
-Shortcut for ``aggregate(MakeLine(<field>))``.
-
-``unionagg``
-~~~~~~~~~~~~
-
-.. method:: GeoQuerySet.unionagg(**kwargs)
-
-.. deprecated:: 1.8
-
-    Use the :class:`Union` aggregate instead.
-
-Shortcut for ``aggregate(Union(<field>))``.
-
 Aggregate Functions
 -------------------
 

+ 1 - 2
docs/releases/1.2.txt

@@ -358,8 +358,7 @@ Support for 3D geometry fields was added, and may be enabled
 by setting the :attr:`~django.contrib.gis.db.models.GeometryField.dim`
 keyword to 3 in your :class:`~django.contrib.gis.db.models.GeometryField`.
 The :class:`~django.contrib.gis.db.models.Extent3D` aggregate
-and :meth:`~django.contrib.gis.db.models.GeoQuerySet.extent3d` ``GeoQuerySet``
-method were added as a part of this feature.
+and ``extent3d()`` ``GeoQuerySet`` method were added as a part of this feature.
 
 The following :class:`~django.contrib.gis.db.models.GeoQuerySet`
 methods are new in 1.2:

+ 3 - 9
tests/gis_tests/geo3d/tests.py

@@ -12,9 +12,7 @@ from django.contrib.gis.gdal import HAS_GDAL
 from django.contrib.gis.geos import GEOSGeometry, LineString, Point, Polygon
 from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
 from django.utils._os import upath
-from django.utils.deprecation import (
-    RemovedInDjango20Warning, RemovedInDjango110Warning,
-)
+from django.utils.deprecation import RemovedInDjango20Warning
 
 from .models import (
     City3D, Interstate2D, Interstate3D, InterstateProj2D, InterstateProj3D,
@@ -217,7 +215,6 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
         self.assertSetEqual({p.ewkt for p in ref_union}, {p.ewkt for p in union})
 
     @skipUnlessDBFeature("supports_3d_functions")
-    @ignore_warnings(category=RemovedInDjango110Warning)
     def test_extent(self):
         """
         Testing the Extent3D aggregate for 3D models.
@@ -225,16 +222,13 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
         self._load_city_data()
         # `SELECT ST_Extent3D(point) FROM geo3d_city3d;`
         ref_extent3d = (-123.305196, -41.315268, 14, 174.783117, 48.462611, 1433)
-        extent1 = City3D.objects.aggregate(Extent3D('point'))['point__extent3d']
-        extent2 = City3D.objects.extent3d()
+        extent = City3D.objects.aggregate(Extent3D('point'))['point__extent3d']
 
         def check_extent3d(extent3d, tol=6):
             for ref_val, ext_val in zip(ref_extent3d, extent3d):
                 self.assertAlmostEqual(ref_val, ext_val, tol)
 
-        for e3d in [extent1, extent2]:
-            check_extent3d(e3d)
-        self.assertIsNone(City3D.objects.none().extent3d())
+        check_extent3d(extent)
         self.assertIsNone(City3D.objects.none().aggregate(Extent3D('point'))['point__extent3d'])
 
     @ignore_warnings(category=RemovedInDjango20Warning)

+ 2 - 2
tests/gis_tests/geoapp/feeds.py

@@ -23,8 +23,8 @@ class TestGeoRSS2(TestGeoRSS1):
     def geometry(self, obj):
         # This should attach a <georss:box> element for the extent of
         # of the cities in the database.  This tuple came from
-        # calling `City.objects.extent()` -- we can't do that call here
-        # because `extent` is not implemented for MySQL/Oracle.
+        # calling `City.objects.aggregate(Extent())` -- we can't do that call
+        # here because `Extent` is not implemented for MySQL/Oracle.
         return (-123.30, -41.32, 174.78, 48.46)
 
     def item_geometry(self, item):

+ 14 - 35
tests/gis_tests/geoapp/tests.py

@@ -13,9 +13,7 @@ from django.core.management import call_command
 from django.db import connection
 from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
 from django.utils import six
-from django.utils.deprecation import (
-    RemovedInDjango20Warning, RemovedInDjango110Warning,
-)
+from django.utils.deprecation import RemovedInDjango20Warning
 
 from ..utils import no_oracle, oracle, postgis, spatialite
 from .models import (
@@ -493,11 +491,9 @@ class GeoQuerySetTest(TestCase):
             self.assertIsInstance(country.envelope, Polygon)
 
     @skipUnlessDBFeature("supports_extent_aggr")
-    @ignore_warnings(category=RemovedInDjango110Warning)
     def test_extent(self):
         """
-        Testing the (deprecated) `extent` GeoQuerySet method and the Extent
-        aggregate.
+        Testing the `Extent` aggregate.
         """
         # Reference query:
         # `SELECT ST_extent(point) FROM geoapp_city WHERE (name='Houston' or name='Dallas');`
@@ -505,13 +501,9 @@ class GeoQuerySetTest(TestCase):
         expected = (-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820)
 
         qs = City.objects.filter(name__in=('Houston', 'Dallas'))
-        extent1 = qs.extent()
-        extent2 = qs.aggregate(Extent('point'))['point__extent']
-
-        for extent in (extent1, extent2):
-            for val, exp in zip(extent, expected):
-                self.assertAlmostEqual(exp, val, 4)
-        self.assertIsNone(City.objects.filter(name=('Smalltown')).extent())
+        extent = qs.aggregate(Extent('point'))['point__extent']
+        for val, exp in zip(extent, expected):
+            self.assertAlmostEqual(exp, val, 4)
         self.assertIsNone(City.objects.filter(name=('Smalltown')).aggregate(Extent('point'))['point__extent'])
 
     @skipUnlessDBFeature("supports_extent_aggr")
@@ -651,11 +643,9 @@ class GeoQuerySetTest(TestCase):
         for ptown in [ptown1, ptown2]:
             self.assertEqual('<Point><coordinates>-104.609252,38.255001</coordinates></Point>', ptown.kml)
 
-    @ignore_warnings(category=RemovedInDjango110Warning)
     def test_make_line(self):
         """
-        Testing the (deprecated) `make_line` GeoQuerySet method and the MakeLine
-        aggregate.
+        Testing the `MakeLine` aggregate.
         """
         if not connection.features.supports_make_line_aggr:
             # Only PostGIS has support for the MakeLine aggregate. For other
@@ -666,9 +656,6 @@ class GeoQuerySetTest(TestCase):
             )
             return
 
-        # Ensuring that a `TypeError` is raised on models without PointFields.
-        self.assertRaises(TypeError, State.objects.make_line)
-        self.assertRaises(TypeError, Country.objects.make_line)
         # MakeLine on an inappropriate field returns simply None
         self.assertIsNone(State.objects.aggregate(MakeLine('poly'))['poly__makeline'])
         # Reference query:
@@ -681,11 +668,11 @@ class GeoQuerySetTest(TestCase):
         )
         # We check for equality with a tolerance of 10e-5 which is a lower bound
         # of the precisions of ref_line coordinates
-        line1 = City.objects.make_line()
-        line2 = City.objects.aggregate(MakeLine('point'))['point__makeline']
-        for line in (line1, line2):
-            self.assertTrue(ref_line.equals_exact(line, tolerance=10e-5),
-                "%s != %s" % (ref_line, line))
+        line = City.objects.aggregate(MakeLine('point'))['point__makeline']
+        self.assertTrue(
+            ref_line.equals_exact(line, tolerance=10e-5),
+            "%s != %s" % (ref_line, line)
+        )
 
     @skipUnlessDBFeature("has_num_geom_method")
     def test_num_geom(self):
@@ -863,33 +850,25 @@ class GeoQuerySetTest(TestCase):
     # but this seems unexpected and should be investigated to determine the cause.
     @skipUnlessDBFeature("has_unionagg_method")
     @no_oracle
-    @ignore_warnings(category=RemovedInDjango110Warning)
     def test_unionagg(self):
         """
-        Testing the (deprecated) `unionagg` (aggregate union) GeoQuerySet method
-        and the Union aggregate.
+        Testing the `Union` aggregate.
         """
         tx = Country.objects.get(name='Texas').mpoly
         # Houston, Dallas -- Ordering may differ depending on backend or GEOS version.
         union1 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
         union2 = fromstr('MULTIPOINT(-95.363151 29.763374,-96.801611 32.782057)')
         qs = City.objects.filter(point__within=tx)
-        self.assertRaises(TypeError, qs.unionagg, 'name')
         self.assertRaises(ValueError, qs.aggregate, Union('name'))
         # Using `field_name` keyword argument in one query and specifying an
         # order in the other (which should not be used because this is
         # an aggregate method on a spatial column)
-        u1 = qs.unionagg(field_name='point')
-        u2 = qs.order_by('name').unionagg()
-        u3 = qs.aggregate(Union('point'))['point__union']
-        u4 = qs.order_by('name').aggregate(Union('point'))['point__union']
+        u1 = qs.aggregate(Union('point'))['point__union']
+        u2 = qs.order_by('name').aggregate(Union('point'))['point__union']
         tol = 0.00001
         self.assertTrue(union1.equals_exact(u1, tol) or union2.equals_exact(u1, tol))
         self.assertTrue(union1.equals_exact(u2, tol) or union2.equals_exact(u2, tol))
-        self.assertTrue(union1.equals_exact(u3, tol) or union2.equals_exact(u3, tol))
-        self.assertTrue(union1.equals_exact(u4, tol) or union2.equals_exact(u4, tol))
         qs = City.objects.filter(name='NotACity')
-        self.assertIsNone(qs.unionagg(field_name='point'))
         self.assertIsNone(qs.aggregate(Union('point'))['point__union'])
 
     def test_within_subquery(self):

+ 14 - 22
tests/gis_tests/relatedapp/tests.py

@@ -4,10 +4,9 @@ from django.contrib.gis.db.models import F, Collect, Count, Extent, Union
 from django.contrib.gis.geometry.backend import Geometry
 from django.contrib.gis.geos import GEOSGeometry, MultiPoint, Point
 from django.db import connection
-from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
+from django.test import TestCase, skipUnlessDBFeature
 from django.test.utils import override_settings
 from django.utils import timezone
-from django.utils.deprecation import RemovedInDjango110Warning
 
 from ..utils import no_oracle
 from .models import (
@@ -64,17 +63,16 @@ class RelatedGeoModelTest(TestCase):
             check_pnt(GEOSGeometry(wkt, srid), qs[0].location.point)
 
     @skipUnlessDBFeature("supports_extent_aggr")
-    @ignore_warnings(category=RemovedInDjango110Warning)
     def test_related_extent_aggregate(self):
-        "Testing the `extent` GeoQuerySet aggregates on related geographic models."
+        "Testing the `Extent` aggregate on related geographic models."
         # This combines the Extent and Union aggregates into one query
         aggs = City.objects.aggregate(Extent('location__point'))
 
         # One for all locations, one that excludes New Mexico (Roswell).
         all_extent = (-104.528056, 29.763374, -79.460734, 40.18476)
         txpa_extent = (-97.516111, 29.763374, -79.460734, 40.18476)
-        e1 = City.objects.extent(field_name='location__point')
-        e2 = City.objects.exclude(state='NM').extent(field_name='location__point')
+        e1 = City.objects.aggregate(Extent('location__point'))['location__point__extent']
+        e2 = City.objects.exclude(state='NM').aggregate(Extent('location__point'))['location__point__extent']
         e3 = aggs['location__point__extent']
 
         # The tolerance value is to four decimal places because of differences
@@ -98,9 +96,8 @@ class RelatedGeoModelTest(TestCase):
         )
 
     @skipUnlessDBFeature("has_unionagg_method")
-    @ignore_warnings(category=RemovedInDjango110Warning)
     def test_related_union_aggregate(self):
-        "Testing the `unionagg` GeoQuerySet aggregates on related geographic models."
+        "Testing the `Union` aggregate on related geographic models."
         # This combines the Extent and Union aggregates into one query
         aggs = City.objects.aggregate(Union('location__point'))
 
@@ -114,14 +111,14 @@ class RelatedGeoModelTest(TestCase):
 
         # The second union aggregate is for a union
         # query that includes limiting information in the WHERE clause (in other
-        # words a `.filter()` precedes the call to `.unionagg()`).
+        # words a `.filter()` precedes the call to `.aggregate(Union()`).
         ref_u1 = MultiPoint(p1, p2, p4, p5, p3, srid=4326)
         ref_u2 = MultiPoint(p2, p3, srid=4326)
 
-        u1 = City.objects.unionagg(field_name='location__point')
+        u1 = City.objects.aggregate(Union('location__point'))['location__point__union']
         u2 = City.objects.exclude(
             name__in=('Roswell', 'Houston', 'Dallas', 'Fort Worth'),
-        ).unionagg(field_name='location__point')
+        ).aggregate(Union('location__point'))['location__point__union']
         u3 = aggs['location__point__union']
         self.assertEqual(type(u1), MultiPoint)
         self.assertEqual(type(u3), MultiPoint)
@@ -291,11 +288,9 @@ class RelatedGeoModelTest(TestCase):
         self.assertIsNone(b.author)
 
     @skipUnlessDBFeature("supports_collect_aggr")
-    @ignore_warnings(category=RemovedInDjango110Warning)
     def test_collect(self):
         """
-        Testing the (deprecated) `collect` GeoQuerySet method and `Collect`
-        aggregate.
+        Testing the `Collect` aggregate.
         """
         # Reference query:
         # SELECT AsText(ST_Collect("relatedapp_location"."point")) FROM "relatedapp_city" LEFT OUTER JOIN
@@ -306,14 +301,11 @@ class RelatedGeoModelTest(TestCase):
             '-95.363151 29.763374,-96.801611 32.782057)'
         )
 
-        c1 = City.objects.filter(state='TX').collect(field_name='location__point')
-        c2 = City.objects.filter(state='TX').aggregate(Collect('location__point'))['location__point__collect']
-
-        for coll in (c1, c2):
-            # Even though Dallas and Ft. Worth share same point, Collect doesn't
-            # consolidate -- that's why 4 points in MultiPoint.
-            self.assertEqual(4, len(coll))
-            self.assertTrue(ref_geom.equals(coll))
+        coll = City.objects.filter(state='TX').aggregate(Collect('location__point'))['location__point__collect']
+        # Even though Dallas and Ft. Worth share same point, Collect doesn't
+        # consolidate -- that's why 4 points in MultiPoint.
+        self.assertEqual(4, len(coll))
+        self.assertTrue(ref_geom.equals(coll))
 
     def test15_invalid_select_related(self):
         "Testing doing select_related on the related name manager of a unique FK. See #13934."