Refs #24152 -- Removed deprecated GeoQuerySet aggregate methods.

Per deprecation timeline.
This commit is contained in:
Tim Graham 2015-09-02 19:55:55 -04:00
parent b6ea1961eb
commit 5d383549ee
7 changed files with 35 additions and 233 deletions

View File

@ -1,6 +1,5 @@
import warnings import warnings
from django.contrib.gis.db.models import aggregates
from django.contrib.gis.db.models.fields import ( from django.contrib.gis.db.models.fields import (
GeometryField, LineStringField, PointField, get_srid_info, 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.fields import Field
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from django.utils import six from django.utils import six
from django.utils.deprecation import ( from django.utils.deprecation import RemovedInDjango20Warning
RemovedInDjango20Warning, RemovedInDjango110Warning,
)
class GeoQuerySet(QuerySet): class GeoQuerySet(QuerySet):
@ -62,19 +59,6 @@ class GeoQuerySet(QuerySet):
""" """
return self._geom_attribute('centroid', **kwargs) 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): def difference(self, geom, **kwargs):
""" """
Returns the spatial difference of the geographic field in a `difference` Returns the spatial difference of the geographic field in a `difference`
@ -108,31 +92,6 @@ class GeoQuerySet(QuerySet):
""" """
return self._geom_attribute('envelope', **kwargs) 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): def force_rhr(self, **kwargs):
""" """
Returns a modified version of the Polygon/MultiPolygon in which Returns a modified version of the Polygon/MultiPolygon in which
@ -227,19 +186,6 @@ class GeoQuerySet(QuerySet):
""" """
return self._distance_attribute('length', None, **kwargs) 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): def mem_size(self, **kwargs):
""" """
Returns the memory size (number of bytes) that the geometry field takes 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) 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. ### # ### Private API -- Abstracted DRY routines. ###
def _spatial_setup(self, att, desc=None, field_name=None, geo_field_type=None): 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 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): def _spatial_attribute(self, att, settings, field_name=None, model_att=None):
""" """
DRY routine for calling a spatial stored procedure on a geometry column DRY routine for calling a spatial stored procedure on a geometry column

View File

@ -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 geometry field in a ``num_points`` attribute on each element of
the ``GeoQuerySet``; otherwise sets with ``None``. 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 Aggregate Functions
------------------- -------------------

View File

@ -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` by setting the :attr:`~django.contrib.gis.db.models.GeometryField.dim`
keyword to 3 in your :class:`~django.contrib.gis.db.models.GeometryField`. keyword to 3 in your :class:`~django.contrib.gis.db.models.GeometryField`.
The :class:`~django.contrib.gis.db.models.Extent3D` aggregate The :class:`~django.contrib.gis.db.models.Extent3D` aggregate
and :meth:`~django.contrib.gis.db.models.GeoQuerySet.extent3d` ``GeoQuerySet`` and ``extent3d()`` ``GeoQuerySet`` method were added as a part of this feature.
method were added as a part of this feature.
The following :class:`~django.contrib.gis.db.models.GeoQuerySet` The following :class:`~django.contrib.gis.db.models.GeoQuerySet`
methods are new in 1.2: methods are new in 1.2:

View File

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

View File

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

View File

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

View File

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