Deprecated legacy GeoManager/GeoQuerySet methods

This commit is contained in:
Claude Paroz 2015-01-29 20:12:08 +01:00
parent 71e20814fc
commit ea27e26b09
10 changed files with 70 additions and 9 deletions

View File

@ -1,5 +1,8 @@
import warnings
from django.contrib.gis.db.models.query import GeoQuerySet
from django.db.models.manager import Manager
from django.utils.deprecation import RemovedInDjango21Warning
class GeoManager(Manager.from_queryset(GeoQuerySet)):
@ -9,3 +12,11 @@ class GeoManager(Manager.from_queryset(GeoQuerySet)):
# so that geometry columns on Oracle and MySQL are selected
# properly.
use_for_related_fields = True
def __init__(self, *args, **kwargs):
warnings.warn(
"The GeoManager class is deprecated. Simply use a normal manager "
"once you have replaced all calls to GeoQuerySet methods by annotations.",
RemovedInDjango21Warning, stacklevel=2
)
super(GeoManager, self).__init__(*args, **kwargs)

View File

@ -15,7 +15,9 @@ 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
from django.utils.deprecation import (
RemovedInDjango20Warning, RemovedInDjango21Warning,
)
class GeoQuerySet(QuerySet):
@ -513,6 +515,11 @@ class GeoQuerySet(QuerySet):
The name of the model attribute to attach the output of
the spatial function to.
"""
warnings.warn(
"The %s GeoQuerySet method is deprecated. See GeoDjango Functions "
"documentation to find the expression-based replacement." % att,
RemovedInDjango21Warning, stacklevel=2
)
# Default settings.
settings.setdefault('desc', None)
settings.setdefault('geom_args', ())

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
from django.apps import apps
from django.contrib.gis.db.models.fields import GeometryField
from django.contrib.gis.db.models.functions import AsKML, Transform
from django.contrib.gis.shortcuts import render_to_kml, render_to_kmz
from django.core.exceptions import FieldDoesNotExist
from django.db import DEFAULT_DB_ALIAS, connections
@ -31,15 +32,17 @@ def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB
connection = connections[using]
if connection.features.has_kml_method:
if connection.features.has_AsKML_function:
# Database will take care of transformation.
placemarks = klass._default_manager.using(using).kml(field_name=field_name)
placemarks = klass._default_manager.using(using).annotate(kml=AsKML(field_name))
else:
# If the database offers no KML method, we use the `kml`
# attribute of the lazy geometry instead.
placemarks = []
if connection.features.has_transform_method:
qs = klass._default_manager.using(using).transform(4326, field_name=field_name)
if connection.features.has_Transform_function:
qs = klass._default_manager.using(using).annotate(
**{'%s_4326' % field_name: Transform(field_name, 4326)})
field_name += '_4326'
else:
qs = klass._default_manager.using(using).all()
for mod in qs:

View File

@ -35,6 +35,8 @@ details on these changes.
* The ``django.contrib.auth.tests.utils.skipIfCustomUser()`` decorator will be
removed.
* The ``GeoManager`` and ``GeoQuerySet`` classes will be removed.
.. _deprecation-removed-in-2.0:
2.0

View File

@ -400,6 +400,16 @@ of its methods and attributes are either changed or renamed.
The aim of these changes is to provide a documented API for relation fields.
``GeoManager`` and ``GeoQuerySet`` custom methods
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All custom ``GeoQuerySet`` methods (``area()``, ``distance()``, ``gml()``, ...)
have been replaced by equivalent geographic expressions in annotations (see in
new features). Hence the need to set a custom ``GeoManager`` to GIS-enabled
models is now obsolete. As soon as your code doesn't call any of the deprecated
methods, you can simply remove the ``objects = GeoManager()`` lines from your
models.
Miscellaneous
~~~~~~~~~~~~~

View File

@ -7,7 +7,8 @@ from django.contrib.gis.geos import HAS_GEOS
from django.contrib.gis.measure import D # alias for Distance
from django.db import connection
from django.db.models import Q
from django.test import TestCase, skipUnlessDBFeature
from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
from django.utils.deprecation import RemovedInDjango21Warning
from ..utils import no_oracle, oracle, postgis, spatialite
@ -98,6 +99,7 @@ class DistanceTest(TestCase):
self.assertListEqual(au_cities, self.get_names(qs.filter(point__dwithin=(self.au_pnt, dist))))
@skipUnlessDBFeature("has_distance_method")
@ignore_warnings(category=RemovedInDjango21Warning)
def test_distance_projected(self):
"""
Test the `distance` GeoQuerySet method on projected coordinate systems.
@ -141,6 +143,7 @@ class DistanceTest(TestCase):
self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, tol)
@skipUnlessDBFeature("has_distance_method", "supports_distance_geodetic")
@ignore_warnings(category=RemovedInDjango21Warning)
def test_distance_geodetic(self):
"""
Test the `distance` GeoQuerySet method on geodetic coordinate systems.
@ -202,6 +205,7 @@ class DistanceTest(TestCase):
@no_oracle # Oracle already handles geographic distance calculation.
@skipUnlessDBFeature("has_distance_method")
@ignore_warnings(category=RemovedInDjango21Warning)
def test_distance_transform(self):
"""
Test the `distance` GeoQuerySet method used with `transform` on a geographic field.
@ -322,6 +326,7 @@ class DistanceTest(TestCase):
self.assertEqual(cities, ['Adelaide', 'Hobart', 'Shellharbour', 'Thirroul'])
@skipUnlessDBFeature("has_area_method")
@ignore_warnings(category=RemovedInDjango21Warning)
def test_area(self):
"""
Test the `area` GeoQuerySet method.
@ -335,6 +340,7 @@ class DistanceTest(TestCase):
self.assertAlmostEqual(area_sq_m[i], z.area.sq_m, tol)
@skipUnlessDBFeature("has_length_method")
@ignore_warnings(category=RemovedInDjango21Warning)
def test_length(self):
"""
Test the `length` GeoQuerySet method.
@ -358,6 +364,7 @@ class DistanceTest(TestCase):
self.assertAlmostEqual(len_m2, i10.length.m, 2)
@skipUnlessDBFeature("has_perimeter_method")
@ignore_warnings(category=RemovedInDjango21Warning)
def test_perimeter(self):
"""
Test the `perimeter` GeoQuerySet method.
@ -374,6 +381,7 @@ class DistanceTest(TestCase):
self.assertEqual(0, c.perim.m)
@skipUnlessDBFeature("has_area_method", "has_distance_method")
@ignore_warnings(category=RemovedInDjango21Warning)
def test_measurement_null_fields(self):
"""
Test the measurement GeoQuerySet methods on fields with NULL values.
@ -388,6 +396,7 @@ class DistanceTest(TestCase):
self.assertIsNone(z.area)
@skipUnlessDBFeature("has_distance_method")
@ignore_warnings(category=RemovedInDjango21Warning)
def test_distance_order_by(self):
qs = SouthTexasCity.objects.distance(Point(3, 3)).order_by(
'distance'

View File

@ -11,7 +11,9 @@ from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.geos import HAS_GEOS
from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
from django.utils._os import upath
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.deprecation import (
RemovedInDjango20Warning, RemovedInDjango21Warning,
)
if HAS_GEOS:
from django.contrib.gis.db.models import Union, Extent3D
@ -172,6 +174,7 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
lm.save()
self.assertEqual(3, MultiPoint3D.objects.count())
@ignore_warnings(category=RemovedInDjango21Warning)
def test_kml(self):
"""
Test GeoQuerySet.kml() with Z values.
@ -183,6 +186,7 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
ref_kml_regex = re.compile(r'^<Point><coordinates>-95.363\d+,29.763\d+,18</coordinates></Point>$')
self.assertTrue(ref_kml_regex.match(h.kml))
@ignore_warnings(category=RemovedInDjango21Warning)
def test_geojson(self):
"""
Test GeoQuerySet.geojson() with Z values.
@ -234,6 +238,7 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
self.assertIsNone(City3D.objects.none().extent3d())
self.assertIsNone(City3D.objects.none().aggregate(Extent3D('point'))['point__extent3d'])
@ignore_warnings(category=RemovedInDjango21Warning)
@skipUnlessDBFeature("supports_3d_functions")
def test_perimeter(self):
"""
@ -252,6 +257,7 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
Polygon3D.objects.perimeter().get(name='3D BBox').perimeter.m,
tol)
@ignore_warnings(category=RemovedInDjango21Warning)
@skipUnlessDBFeature("supports_3d_functions")
def test_length(self):
"""
@ -285,6 +291,7 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
InterstateProj3D.objects.length().get(name='I-45').length.m,
tol)
@ignore_warnings(category=RemovedInDjango21Warning)
@skipUnlessDBFeature("supports_3d_functions")
def test_scale(self):
"""
@ -297,6 +304,7 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
for city in City3D.objects.scale(1.0, 1.0, zscale):
self.assertEqual(city_dict[city.name][2] * zscale, city.scale.z)
@ignore_warnings(category=RemovedInDjango21Warning)
@skipUnlessDBFeature("supports_3d_functions")
def test_translate(self):
"""

View File

@ -9,7 +9,9 @@ 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
from django.utils.deprecation import (
RemovedInDjango20Warning, RemovedInDjango21Warning,
)
from ..utils import no_oracle, oracle, postgis, spatialite
@ -431,6 +433,7 @@ class GeoLookupTest(TestCase):
@skipUnlessDBFeature("gis_enabled")
@ignore_warnings(category=RemovedInDjango21Warning)
class GeoQuerySetTest(TestCase):
fixtures = ['initial']

View File

@ -10,8 +10,9 @@ from django.contrib.gis.db.models.functions import Area, Distance
from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.geos import HAS_GEOS
from django.contrib.gis.measure import D
from django.test import TestCase, skipUnlessDBFeature
from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
from django.utils._os import upath
from django.utils.deprecation import RemovedInDjango21Warning
from ..utils import oracle, postgis
@ -43,6 +44,7 @@ class GeographyTest(TestCase):
self.assertEqual(['Dallas', 'Houston', 'Oklahoma City'], cities)
@skipUnlessDBFeature("has_distance_method", "supports_distance_geodetic")
@ignore_warnings(category=RemovedInDjango21Warning)
def test03_distance_method(self):
"Testing GeoQuerySet.distance() support on non-point geography fields."
# `GeoQuerySet.distance` is not allowed geometry fields.
@ -95,6 +97,7 @@ class GeographyTest(TestCase):
self.assertEqual(state, c.state)
@skipUnlessDBFeature("has_area_method", "supports_distance_geodetic")
@ignore_warnings(category=RemovedInDjango21Warning)
def test06_geography_area(self):
"Testing that Area calculations work on geography columns."
# SELECT ST_Area(poly) FROM geogapp_zipcode WHERE code='77002';

View File

@ -158,6 +158,11 @@ def setup(verbosity, test_labels):
'django.contrib.webdesign will be removed in Django 2.0.',
RemovedInDjango20Warning
)
warnings.filterwarnings(
'ignore',
'The GeoManager class is deprecated.',
RemovedInDjango21Warning
)
# Load all the ALWAYS_INSTALLED_APPS.
django.setup()