Kaydet (Commit) a0d16630 authored tarafından Tim Graham's avatar Tim Graham

Removed GeoManager and GeoQuerySet per deprecation timeline.

üst e90c745a
import re
from functools import partial
from django.contrib.gis.db.models import aggregates
......@@ -71,17 +70,6 @@ class BaseSpatialFeatures(object):
def supports_isvalid_lookup(self):
return 'isvalid' in self.connection.ops.gis_operators
# For each of those methods, the class will have a property named
# `has_<name>_method` (defined in __init__) which accesses connection.ops
# to determine GIS method availability.
geoqueryset_methods = (
'area', 'bounding_circle', 'centroid', 'difference', 'distance',
'distance_spheroid', 'envelope', 'force_rhr', 'geohash', 'gml',
'intersection', 'kml', 'length', 'mem_size', 'num_geom', 'num_points',
'perimeter', 'point_on_surface', 'reverse', 'scale', 'snap_to_grid',
'svg', 'sym_difference', 'transform', 'translate', 'union', 'unionagg',
)
# Is the aggregate supported by the database?
@property
def supports_collect_aggr(self):
......@@ -99,19 +87,9 @@ class BaseSpatialFeatures(object):
def supports_union_aggr(self):
return aggregates.Union not in self.connection.ops.disallowed_aggregates
def __init__(self, *args):
super(BaseSpatialFeatures, self).__init__(*args)
for method in self.geoqueryset_methods:
# Add dynamically properties for each GQS method, e.g. has_force_rhr_method, etc.
setattr(self.__class__, 'has_%s_method' % method,
property(partial(BaseSpatialFeatures.has_ops_method, method=method)))
def __getattr__(self, name):
m = re.match(r'has_(\w*)_function$', name)
if m:
func_name = m.group(1)
return func_name not in self.connection.ops.unsupported_functions
raise AttributeError
def has_ops_method(self, method):
return getattr(self.connection.ops, method, False)
......@@ -55,7 +55,6 @@ class OracleSpatialRefSys(models.Model, SpatialRefSysMixin):
# Optional geometry representing the bounds of this coordinate
# system. By default, all are NULL in the table.
cs_bounds = models.PolygonField(null=True)
objects = models.GeoManager()
class Meta:
app_label = 'gis'
......
......@@ -7,11 +7,10 @@ from django.contrib.gis.db.models.fields import (
MultiLineStringField, MultiPointField, MultiPolygonField, PointField,
PolygonField, RasterField,
)
from django.contrib.gis.db.models.manager import GeoManager
__all__ = models_all + aggregates_all
__all__ += [
'GeometryCollectionField', 'GeometryField', 'LineStringField',
'MultiLineStringField', 'MultiPointField', 'MultiPolygonField', 'PointField',
'PolygonField', 'RasterField', 'GeoManager',
'PolygonField', 'RasterField',
]
......@@ -346,27 +346,6 @@ class GeometryField(GeoSelectFormatMixin, BaseSpatialField):
defaults['widget'] = forms.Textarea
return super(GeometryField, self).formfield(**defaults)
def _get_db_prep_lookup(self, lookup_type, value, connection):
"""
Prepare for the database lookup, and return any spatial parameters
necessary for the query. This includes wrapping any geometry
parameters with a backend-specific adapter and formatting any distance
parameters into the correct units for the coordinate system of the
field.
Only used by the deprecated GeoQuerySet and to be
RemovedInDjango20Warning.
"""
# Populating the parameters list, and wrapping the Geometry
# with the Adapter of the spatial backend.
if isinstance(value, (tuple, list)):
params = [connection.ops.Adapter(value[0])]
# Getting the distance parameter in the units of the field.
params += self.get_distance(value[1:], lookup_type, connection)
else:
params = [connection.ops.Adapter(value)]
return params
# The OpenGIS Geometry Type Fields
class PointField(GeometryField):
......
import warnings
from django.contrib.gis.db.models.query import GeoQuerySet
from django.db.models.manager import Manager
from django.utils.deprecation import RemovedInDjango20Warning
class GeoManager(Manager.from_queryset(GeoQuerySet)):
"Overrides Manager to return Geographic QuerySets."
# This manager should be used for queries on related fields
# so that geometry columns on Oracle and MySQL are selected
# properly.
use_for_related_fields = True
# No need to bother users with the use_for_related_fields
# deprecation for this manager which is itself deprecated.
silence_use_for_related_fields_deprecation = 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.",
RemovedInDjango20Warning, stacklevel=2
)
super(GeoManager, self).__init__(*args, **kwargs)
This diff is collapsed.
......@@ -244,22 +244,6 @@ For more information, the PostGIS documentation contains a helpful section on
determining `when to use geography data type over geometry data type
<http://postgis.net/docs/using_postgis_dbmanagement.html#PostGIS_GeographyVSGeometry>`_.
``GeoManager``
==============
.. currentmodule:: django.contrib.gis.db.models
.. class:: GeoManager
The ``GeoManager`` is required in order to use the legacy
:ref:`geoqueryset-methods`.
.. deprecated:: 1.9
All ``GeoQuerySet`` methods have been deprecated and replaced by
:doc:`equivalent database functions </ref/contrib/gis/functions>`. As soon
as the legacy methods have been replaced in your code, you should be able
to remove the special ``GeoManager`` from your GIS-enabled classes.
.. rubric:: Footnotes
.. [#fnogc] OpenGIS Consortium, Inc., `Simple Feature Specification For SQL <http://www.opengeospatial.org/standards/sfs>`_.
.. [#fnogcsrid] *See id.* at Ch. 2.3.8, p. 39 (Geometry Values and Spatial Reference Systems).
......
......@@ -149,11 +149,10 @@ Here's the formal declaration of a ``QuerySet``:
.. note::
The ``query`` parameter to :class:`QuerySet` exists so that specialized
query subclasses such as
:class:`~django.contrib.gis.db.models.GeoQuerySet` can reconstruct
internal query state. The value of the parameter is an opaque
representation of that query state and is not part of a public API.
To put it simply: if you need to ask, you don't need to use it.
query subclasses can reconstruct internal query state. The value of the
parameter is an opaque representation of that query state and is not
part of a public API. To put it simply: if you need to ask, you don't
need to use it.
.. currentmodule:: django.db.models.query.QuerySet
......
......@@ -359,12 +359,8 @@ keyword to 3 in your :class:`~django.contrib.gis.db.models.GeometryField`.
The :class:`~django.contrib.gis.db.models.Extent3D` aggregate
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:
* :meth:`~django.contrib.gis.db.models.GeoQuerySet.force_rhr`
* :meth:`~django.contrib.gis.db.models.GeoQuerySet.reverse_geom`
* :meth:`~django.contrib.gis.db.models.GeoQuerySet.geohash`
The ``force_rhr()``, ``reverse_geom()``, and ``geohash()`` ``GeoQuerySet``
methods are new.
The GEOS interface was updated to use thread-safe C library functions when
available on the platform.
......
......@@ -261,3 +261,5 @@ these features.
ORM, e.g. with ``cursor.execute()``.
* ``django.contrib.auth.tests.utils.skipIfCustomUser()`` is removed.
* The ``GeoManager`` and ``GeoQuerySet`` classes are removed.
......@@ -8,8 +8,6 @@ from ..utils import gisfield_may_be_null
class NamedModel(models.Model):
name = models.CharField(max_length=30)
objects = models.GeoManager()
class Meta:
abstract = True
required_db_features = ['gis_enabled']
......
......@@ -6,8 +6,6 @@ from django.utils.encoding import python_2_unicode_compatible
class NamedModel(models.Model):
name = models.CharField(max_length=30)
objects = models.GeoManager()
class Meta:
abstract = True
required_db_features = ['gis_enabled']
......
......@@ -8,9 +8,8 @@ from django.contrib.gis.db.models.functions import (
AsGeoJSON, AsKML, Length, Perimeter, Scale, Translate,
)
from django.contrib.gis.geos import GEOSGeometry, LineString, Point, Polygon
from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
from django.test import TestCase, skipUnlessDBFeature
from django.utils._os import upath
from django.utils.deprecation import RemovedInDjango20Warning
from .models import (
City3D, Interstate2D, Interstate3D, InterstateProj2D, InterstateProj3D,
......@@ -171,30 +170,6 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
lm.save()
self.assertEqual(3, MultiPoint3D.objects.count())
@ignore_warnings(category=RemovedInDjango20Warning)
def test_kml(self):
"""
Test GeoQuerySet.kml() with Z values.
"""
self._load_city_data()
h = City3D.objects.kml(precision=6).get(name='Houston')
# KML should be 3D.
# `SELECT ST_AsKML(point, 6) FROM geo3d_city3d WHERE name = 'Houston';`
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=RemovedInDjango20Warning)
def test_geojson(self):
"""
Test GeoQuerySet.geojson() with Z values.
"""
self._load_city_data()
h = City3D.objects.geojson(precision=6).get(name='Houston')
# GeoJSON should be 3D
# `SELECT ST_AsGeoJSON(point, 6) FROM geo3d_city3d WHERE name='Houston';`
ref_json_regex = re.compile(r'^{"type":"Point","coordinates":\[-95.363151,29.763374,18(\.0+)?\]}$')
self.assertTrue(ref_json_regex.match(h.geojson))
@skipUnlessDBFeature("supports_3d_functions")
def test_union(self):
"""
......@@ -231,84 +206,6 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
check_extent3d(extent)
self.assertIsNone(City3D.objects.none().aggregate(Extent3D('point'))['point__extent3d'])
@ignore_warnings(category=RemovedInDjango20Warning)
@skipUnlessDBFeature("supports_3d_functions")
def test_perimeter(self):
"""
Testing GeoQuerySet.perimeter() on 3D fields.
"""
self._load_polygon_data()
# Reference query for values below:
# `SELECT ST_Perimeter3D(poly), ST_Perimeter2D(poly) FROM geo3d_polygon3d;`
ref_perim_3d = 76859.2620451
ref_perim_2d = 76859.2577803
tol = 6
self.assertAlmostEqual(ref_perim_2d,
Polygon2D.objects.perimeter().get(name='2D BBox').perimeter.m,
tol)
self.assertAlmostEqual(ref_perim_3d,
Polygon3D.objects.perimeter().get(name='3D BBox').perimeter.m,
tol)
@ignore_warnings(category=RemovedInDjango20Warning)
@skipUnlessDBFeature("supports_3d_functions")
def test_length(self):
"""
Testing GeoQuerySet.length() on 3D fields.
"""
# ST_Length_Spheroid Z-aware, and thus does not need to use
# a separate function internally.
# `SELECT ST_Length_Spheroid(line, 'SPHEROID["GRS 1980",6378137,298.257222101]')
# FROM geo3d_interstate[2d|3d];`
self._load_interstate_data()
tol = 3
ref_length_2d = 4368.1721949481
ref_length_3d = 4368.62547052088
self.assertAlmostEqual(ref_length_2d,
Interstate2D.objects.length().get(name='I-45').length.m,
tol)
self.assertAlmostEqual(ref_length_3d,
Interstate3D.objects.length().get(name='I-45').length.m,
tol)
# Making sure `ST_Length3D` is used on for a projected
# and 3D model rather than `ST_Length`.
# `SELECT ST_Length(line) FROM geo3d_interstateproj2d;`
ref_length_2d = 4367.71564892392
# `SELECT ST_Length3D(line) FROM geo3d_interstateproj3d;`
ref_length_3d = 4368.16897234101
self.assertAlmostEqual(ref_length_2d,
InterstateProj2D.objects.length().get(name='I-45').length.m,
tol)
self.assertAlmostEqual(ref_length_3d,
InterstateProj3D.objects.length().get(name='I-45').length.m,
tol)
@ignore_warnings(category=RemovedInDjango20Warning)
@skipUnlessDBFeature("supports_3d_functions")
def test_scale(self):
"""
Testing GeoQuerySet.scale() on Z values.
"""
self._load_city_data()
# Mapping of City name to reference Z values.
zscales = (-3, 4, 23)
for zscale in zscales:
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=RemovedInDjango20Warning)
@skipUnlessDBFeature("supports_3d_functions")
def test_translate(self):
"""
Testing GeoQuerySet.translate() on Z values.
"""
self._load_city_data()
ztranslations = (5.23, 23, -17)
for ztrans in ztranslations:
for city in City3D.objects.translate(0, 0, ztrans):
self.assertEqual(city_dict[city.name][2] + ztrans, city.translate.z)
@skipUnlessDBFeature("gis_enabled", "supports_3d_functions")
class Geo3DFunctionsTests(Geo3DLoadingHelper, TestCase):
......
......@@ -8,8 +8,6 @@ from ..utils import gisfield_may_be_null
class NamedModel(models.Model):
name = models.CharField(max_length=30)
objects = models.GeoManager()
class Meta:
abstract = True
required_db_features = ['gis_enabled']
......
......@@ -19,7 +19,6 @@ from .models import City, Country, CountryWebMercator, State, Track
class GISFunctionsTests(TestCase):
"""
Testing functions from django/contrib/gis/db/models/functions.py.
Several tests are taken and adapted from GeoQuerySetTest.
Area/Distance/Length/Perimeter are tested in distapp/tests.
Please keep the tests in function's alphabetic order.
......@@ -462,7 +461,6 @@ class GISFunctionsTests(TestCase):
"has_Difference_function", "has_Intersection_function",
"has_SymDifference_function", "has_Union_function")
def test_diff_intersection_union(self):
"Testing the `difference`, `intersection`, `sym_difference`, and `union` GeoQuerySet methods."
geom = Point(5, 23, srid=4326)
qs = Country.objects.all().annotate(
difference=functions.Difference('mpoly', geom),
......
......@@ -17,7 +17,7 @@ class GeoRegressionTests(TestCase):
fixtures = ['initial']
def test_update(self):
"Testing GeoQuerySet.update(). See #10411."
"Testing QuerySet.update() (#10411)."
pnt = City.objects.get(name='Pueblo').point
bak = pnt.clone()
pnt.y += 0.005
......
This diff is collapsed.
......@@ -6,8 +6,6 @@ from django.utils.encoding import python_2_unicode_compatible
class NamedModel(models.Model):
name = models.CharField(max_length=30)
objects = models.GeoManager()
class Meta:
abstract = True
required_db_features = ['gis_enabled']
......
......@@ -11,11 +11,8 @@ from django.contrib.gis.db.models.functions import Area, Distance
from django.contrib.gis.measure import D
from django.db import connection
from django.db.models.functions import Cast
from django.test import (
TestCase, ignore_warnings, skipIfDBFeature, skipUnlessDBFeature,
)
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils._os import upath
from django.utils.deprecation import RemovedInDjango20Warning
from ..utils import oracle, postgis, spatialite
from .models import City, County, Zipcode
......@@ -32,7 +29,7 @@ class GeographyTest(TestCase):
@skipIf(spatialite, "SpatiaLite doesn't support distance lookups with Distance objects.")
@skipUnlessDBFeature("supports_distances_lookups", "supports_distance_geodetic")
def test02_distance_lookup(self):
"Testing GeoQuerySet distance lookup support on non-point geography fields."
"Testing distance lookup support on non-point geography fields."
z = Zipcode.objects.get(code='77002')
cities1 = list(City.objects
.filter(point__distance_lte=(z.poly, D(mi=500)))
......@@ -45,15 +42,6 @@ class GeographyTest(TestCase):
for cities in [cities1, cities2]:
self.assertEqual(['Dallas', 'Houston', 'Oklahoma City'], cities)
@skipIf(spatialite, "distance() doesn't support geodetic coordinates on SpatiaLite.")
@skipUnlessDBFeature("has_distance_method", "supports_distance_geodetic")
@ignore_warnings(category=RemovedInDjango20Warning)
def test03_distance_method(self):
"Testing GeoQuerySet.distance() support on non-point geography fields."
# `GeoQuerySet.distance` is not allowed geometry fields.
htown = City.objects.get(name='Houston')
Zipcode.objects.distance(htown.point)
@skipUnless(postgis, "This is a PostGIS-specific test")
def test04_invalid_operators_functions(self):
"Ensuring exceptions are raised for operators & functions invalid on geography fields."
......@@ -101,19 +89,6 @@ class GeographyTest(TestCase):
self.assertEqual(name, c.name)
self.assertEqual(state, c.state)
@skipIf(spatialite, "area() doesn't support geodetic coordinates on SpatiaLite.")
@skipUnlessDBFeature("has_area_method", "supports_distance_geodetic")
@ignore_warnings(category=RemovedInDjango20Warning)
def test06_geography_area(self):
"Testing that Area calculations work on geography columns."
# SELECT ST_Area(poly) FROM geogapp_zipcode WHERE code='77002';
z = Zipcode.objects.area().get(code='77002')
# Round to the nearest thousand as possible values (depending on
# the database and geolib) include 5439084, 5439100, 5439101.
rounded_value = z.area.sq_m
rounded_value -= z.area.sq_m % 1000
self.assertEqual(rounded_value, 5439000)
@skipUnlessDBFeature("gis_enabled")
class GeographyFunctionTests(TestCase):
......
......@@ -3,9 +3,6 @@ from django.utils.encoding import python_2_unicode_compatible
class SimpleModel(models.Model):
objects = models.GeoManager()
class Meta:
abstract = True
required_db_features = ['gis_enabled']
......
......@@ -38,33 +38,6 @@ class RelatedGeoModelTest(TestCase):
self.assertEqual(st, c.state)
self.assertEqual(Point(lon, lat, srid=c.location.point.srid), c.location.point)
@skipUnlessDBFeature("has_transform_method")
def test03_transform_related(self):
"Testing the `transform` GeoQuerySet method on related geographic models."
# All the transformations are to state plane coordinate systems using
# US Survey Feet (thus a tolerance of 0 implies error w/in 1 survey foot).
tol = 0
def check_pnt(ref, pnt):
self.assertAlmostEqual(ref.x, pnt.x, tol)
self.assertAlmostEqual(ref.y, pnt.y, tol)
self.assertEqual(ref.srid, pnt.srid)
# Each city transformed to the SRID of their state plane coordinate system.
transformed = (('Kecksburg', 2272, 'POINT(1490553.98959621 314792.131023984)'),
('Roswell', 2257, 'POINT(481902.189077221 868477.766629735)'),
('Aurora', 2276, 'POINT(2269923.2484839 7069381.28722222)'),
)
for name, srid, wkt in transformed:
# Doing this implicitly sets `select_related` select the location.
# TODO: Fix why this breaks on Oracle.
qs = list(City.objects.filter(name=name).transform(srid, field_name='location__point'))
check_pnt(GEOSGeometry(wkt, srid), qs[0].location.point)
# Relations more than one level deep can be queried.
self.assertEqual(list(Parcel.objects.transform(srid, field_name='city__location__point')), [])
@skipUnlessDBFeature("supports_extent_aggr")
def test_related_extent_aggregate(self):
"Testing the `Extent` aggregate on related geographic models."
......@@ -190,13 +163,13 @@ class RelatedGeoModelTest(TestCase):
self.assertEqual('P1', qs[0].name)
def test07_values(self):
"Testing values() and values_list() and GeoQuerySets."
"Testing values() and values_list()."
gqs = Location.objects.all()
gvqs = Location.objects.values()
gvlqs = Location.objects.values_list()
# Incrementing through each of the models, dictionaries, and tuples
# returned by the different types of GeoQuerySets.
# returned by each QuerySet.
for m, d, t in zip(gqs, gvqs, gvlqs):
# The values should be Geometry objects and not raw strings returned
# by the spatial database.
......@@ -234,7 +207,7 @@ class RelatedGeoModelTest(TestCase):
# TODO: fix on Oracle -- qs2 returns an empty result for an unknown reason
@no_oracle
def test10_combine(self):
"Testing the combination of two GeoQuerySets. See #10807."
"Testing the combination of two QuerySets (#10807)."
buf1 = City.objects.get(name='Aurora').location.point.buffer(0.1)
buf2 = City.objects.get(name='Kecksburg').location.point.buffer(0.1)
qs1 = City.objects.filter(location__point__within=buf1)
......
......@@ -305,19 +305,6 @@ class TestManagerInheritance(TestCase):
@isolate_apps('managers_regress')
class TestManagerDeprecations(TestCase):
def test_use_for_related_fields_on_geomanager(self):
from django.contrib.gis.db.models import GeoManager
class MyModel(models.Model):
objects = GeoManager()
# Shouldn't issue any warnings, since GeoManager itself will be
# deprecated at the same time as use_for_related_fields, there
# is no point annoying users with this deprecation.
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter('always', RemovedInDjango20Warning)
MyModel._base_manager
self.assertEqual(len(warns), 0)
def test_use_for_related_fields_for_base_manager(self):
class MyManager(models.Manager):
......
......@@ -168,12 +168,6 @@ def setup(verbosity, test_labels, parallel):
'fields.W901', # CommaSeparatedIntegerField deprecated
]
warnings.filterwarnings(
'ignore',
'The GeoManager class is deprecated.',
RemovedInDjango20Warning
)
# Load all the ALWAYS_INSTALLED_APPS.
django.setup()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment