diff --git a/django/contrib/gis/admin/__init__.py b/django/contrib/gis/admin/__init__.py index 2c3de6f4c5..4837de2029 100644 --- a/django/contrib/gis/admin/__init__.py +++ b/django/contrib/gis/admin/__init__.py @@ -11,7 +11,7 @@ from django.contrib.admin import ( register, site, ) -from django.contrib.gis.admin.options import GeoModelAdmin, GISModelAdmin, OSMGeoAdmin +from django.contrib.gis.admin.options import GISModelAdmin from django.contrib.gis.admin.widgets import OpenLayersWidget __all__ = [ @@ -28,7 +28,5 @@ __all__ = [ "site", "GISModelAdmin", # RemovedInDjango50Warning. - "GeoModelAdmin", "OpenLayersWidget", - "OSMGeoAdmin", ] diff --git a/django/contrib/gis/admin/options.py b/django/contrib/gis/admin/options.py index 9eb6af6335..eece24129b 100644 --- a/django/contrib/gis/admin/options.py +++ b/django/contrib/gis/admin/options.py @@ -1,12 +1,6 @@ -import warnings - from django.contrib.admin import ModelAdmin -from django.contrib.gis.admin.widgets import OpenLayersWidget from django.contrib.gis.db import models from django.contrib.gis.forms import OSMWidget -from django.contrib.gis.gdal import OGRGeomType -from django.forms import Media -from django.utils.deprecation import RemovedInDjango50Warning class GeoModelAdminMixin: @@ -25,156 +19,3 @@ class GeoModelAdminMixin: class GISModelAdmin(GeoModelAdminMixin, ModelAdmin): pass - - -# RemovedInDjango50Warning. -spherical_mercator_srid = 3857 - - -# RemovedInDjango50Warning. -class GeoModelAdmin(ModelAdmin): - """ - The administration options class for Geographic models. Map settings - may be overloaded from their defaults to create custom maps. - """ - - # The default map settings that may be overloaded -- still subject - # to API changes. - default_lon = 0 - default_lat = 0 - default_zoom = 4 - display_wkt = False - display_srid = False - extra_js = [] - num_zoom = 18 - max_zoom = False - min_zoom = False - units = False - max_resolution = False - max_extent = False - modifiable = True - mouse_position = True - scale_text = True - layerswitcher = True - scrollable = True - map_width = 600 - map_height = 400 - map_srid = 4326 - map_template = "gis/admin/openlayers.html" - openlayers_url = ( - "https://cdnjs.cloudflare.com/ajax/libs/openlayers/2.13.1/OpenLayers.js" - ) - point_zoom = num_zoom - 6 - wms_url = "http://vmap0.tiles.osgeo.org/wms/vmap0" - wms_layer = "basic" - wms_name = "OpenLayers WMS" - wms_options = {"format": "image/jpeg"} - debug = False - widget = OpenLayersWidget - - def __init__(self, *args, **kwargs): - warnings.warn( - "django.contrib.gis.admin.GeoModelAdmin and OSMGeoAdmin are " - "deprecated in favor of django.contrib.admin.ModelAdmin and " - "django.contrib.gis.admin.GISModelAdmin.", - RemovedInDjango50Warning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) - - @property - def media(self): - "Injects OpenLayers JavaScript into the admin." - return super().media + Media(js=[self.openlayers_url] + self.extra_js) - - def formfield_for_dbfield(self, db_field, request, **kwargs): - """ - Overloaded from ModelAdmin so that an OpenLayersWidget is used - for viewing/editing 2D GeometryFields (OpenLayers 2 does not support - 3D editing). - """ - if isinstance(db_field, models.GeometryField) and db_field.dim < 3: - # Setting the widget with the newly defined widget. - kwargs["widget"] = self.get_map_widget(db_field) - return db_field.formfield(**kwargs) - else: - return super().formfield_for_dbfield(db_field, request, **kwargs) - - def get_map_widget(self, db_field): - """ - Return a subclass of the OpenLayersWidget (or whatever was specified - in the `widget` attribute) using the settings from the attributes set - in this class. - """ - is_collection = db_field.geom_type in ( - "MULTIPOINT", - "MULTILINESTRING", - "MULTIPOLYGON", - "GEOMETRYCOLLECTION", - ) - if is_collection: - if db_field.geom_type == "GEOMETRYCOLLECTION": - collection_type = "Any" - else: - collection_type = OGRGeomType(db_field.geom_type.replace("MULTI", "")) - else: - collection_type = "None" - - class OLMap(self.widget): - template_name = self.map_template - geom_type = db_field.geom_type - - wms_options = "" - if self.wms_options: - wms_options = ["%s: '%s'" % pair for pair in self.wms_options.items()] - wms_options = ", %s" % ", ".join(wms_options) - - params = { - "default_lon": self.default_lon, - "default_lat": self.default_lat, - "default_zoom": self.default_zoom, - "display_wkt": self.debug or self.display_wkt, - "geom_type": OGRGeomType(db_field.geom_type), - "field_name": db_field.name, - "is_collection": is_collection, - "scrollable": self.scrollable, - "layerswitcher": self.layerswitcher, - "collection_type": collection_type, - "is_generic": db_field.geom_type == "GEOMETRY", - "is_linestring": db_field.geom_type - in ("LINESTRING", "MULTILINESTRING"), - "is_polygon": db_field.geom_type in ("POLYGON", "MULTIPOLYGON"), - "is_point": db_field.geom_type in ("POINT", "MULTIPOINT"), - "num_zoom": self.num_zoom, - "max_zoom": self.max_zoom, - "min_zoom": self.min_zoom, - "units": self.units, # likely should get from object - "max_resolution": self.max_resolution, - "max_extent": self.max_extent, - "modifiable": self.modifiable, - "mouse_position": self.mouse_position, - "scale_text": self.scale_text, - "map_width": self.map_width, - "map_height": self.map_height, - "point_zoom": self.point_zoom, - "srid": self.map_srid, - "display_srid": self.display_srid, - "wms_url": self.wms_url, - "wms_layer": self.wms_layer, - "wms_name": self.wms_name, - "wms_options": wms_options, - "debug": self.debug, - } - - return OLMap - - -# RemovedInDjango50Warning. -class OSMGeoAdmin(GeoModelAdmin): - map_template = "gis/admin/osm.html" - num_zoom = 20 - map_srid = spherical_mercator_srid - max_extent = "-20037508,-20037508,20037508,20037508" - max_resolution = "156543.0339" - point_zoom = num_zoom - 6 - units = "m" diff --git a/django/contrib/gis/templates/gis/admin/openlayers.html b/django/contrib/gis/templates/gis/admin/openlayers.html deleted file mode 100644 index 6943a5beae..0000000000 --- a/django/contrib/gis/templates/gis/admin/openlayers.html +++ /dev/null @@ -1,31 +0,0 @@ -{% block extrastyle %} -{% load i18n static %}{% get_current_language_bidi as LANGUAGE_BIDI %} - -{% endblock %} - - -
-{% if editable %} -{% translate "Delete all Features" %} -{% endif %} -{% if display_wkt %}

{% translate "WKT debugging window:" %}

{% endif %} - - -
diff --git a/django/contrib/gis/templates/gis/admin/openlayers.js b/django/contrib/gis/templates/gis/admin/openlayers.js deleted file mode 100644 index dd00bfd70a..0000000000 --- a/django/contrib/gis/templates/gis/admin/openlayers.js +++ /dev/null @@ -1,176 +0,0 @@ -{% load l10n %} -OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857", OpenLayers.Layer.SphericalMercator.projectForward); -{% block vars %}var {{ module }} = {}; -{{ module }}.map = null; {{ module }}.controls = null; {{ module }}.panel = null; {{ module }}.re = new RegExp("^SRID=\\d+;(.+)", "i"); {{ module }}.layers = {}; -{{ module }}.modifiable = {{ modifiable|yesno:"true,false" }}; -{{ module }}.wkt_f = new OpenLayers.Format.WKT(); -{{ module }}.is_collection = {{ is_collection|yesno:"true,false" }}; -{{ module }}.collection_type = '{{ collection_type }}'; -{{ module }}.is_generic = {{ is_generic|yesno:"true,false" }}; -{{ module }}.is_linestring = {{ is_linestring|yesno:"true,false" }}; -{{ module }}.is_polygon = {{ is_polygon|yesno:"true,false" }}; -{{ module }}.is_point = {{ is_point|yesno:"true,false" }}; -{% endblock %} -{{ module }}.get_ewkt = function(feat){ - return 'SRID={{ srid|unlocalize }};' + {{ module }}.wkt_f.write(feat); -}; -{{ module }}.read_wkt = function(wkt){ - // OpenLayers cannot handle EWKT -- we make sure to strip it out. - // EWKT is only exposed to OL if there's a validation error in the admin. - var match = {{ module }}.re.exec(wkt); - if (match){wkt = match[1];} - return {{ module }}.wkt_f.read(wkt); -}; -{{ module }}.write_wkt = function(feat){ - if ({{ module }}.is_collection){ {{ module }}.num_geom = feat.geometry.components.length;} - else { {{ module }}.num_geom = 1;} - document.getElementById('{{ id }}').value = {{ module }}.get_ewkt(feat); -}; -{{ module }}.add_wkt = function(event){ - // This function will sync the contents of the `vector` layer with the - // WKT in the text field. - if ({{ module }}.is_collection){ - var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}()); - for (var i = 0; i < {{ module }}.layers.vector.features.length; i++){ - feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]); - } - {{ module }}.write_wkt(feat); - } else { - // Make sure to remove any previously added features. - if ({{ module }}.layers.vector.features.length > 1){ - old_feats = [{{ module }}.layers.vector.features[0]]; - {{ module }}.layers.vector.removeFeatures(old_feats); - {{ module }}.layers.vector.destroyFeatures(old_feats); - } - {{ module }}.write_wkt(event.feature); - } -}; -{{ module }}.modify_wkt = function(event){ - if ({{ module }}.is_collection){ - if ({{ module }}.is_point){ - {{ module }}.add_wkt(event); - return; - } else { - // When modifying the selected components are added to the - // vector layer so we only increment to the `num_geom` value. - var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}()); - for (var i = 0; i < {{ module }}.num_geom; i++){ - feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]); - } - {{ module }}.write_wkt(feat); - } - } else { - {{ module }}.write_wkt(event.feature); - } -}; -// Function to clear vector features and purge wkt from div -{{ module }}.deleteFeatures = function(){ - {{ module }}.layers.vector.removeFeatures({{ module }}.layers.vector.features); - {{ module }}.layers.vector.destroyFeatures(); -}; -{{ module }}.clearFeatures = function (){ - {{ module }}.deleteFeatures(); - document.getElementById('{{ id }}').value = ''; - {% localize off %} - {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }}); - {% endlocalize %} -}; -// Add Select control -{{ module }}.addSelectControl = function(){ - var select = new OpenLayers.Control.SelectFeature({{ module }}.layers.vector, {'toggle' : true, 'clickout' : true}); - {{ module }}.map.addControl(select); - select.activate(); -}; -{{ module }}.enableDrawing = function(){ - {{ module }}.map.getControlsByClass('OpenLayers.Control.DrawFeature')[0].activate(); -}; -{{ module }}.enableEditing = function(){ - {{ module }}.map.getControlsByClass('OpenLayers.Control.ModifyFeature')[0].activate(); -}; -// Create an array of controls based on geometry type -{{ module }}.getControls = function(lyr){ - {{ module }}.panel = new OpenLayers.Control.Panel({'displayClass': 'olControlEditingToolbar'}); - {{ module }}.controls = [new OpenLayers.Control.Navigation()]; - if (!{{ module }}.modifiable && lyr.features.length) return; - if ({{ module }}.is_linestring || {{ module }}.is_generic){ - {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath'})); - } - if ({{ module }}.is_polygon || {{ module }}.is_generic){ - {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon'})); - } - if ({{ module }}.is_point || {{ module }}.is_generic){ - {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint'})); - } - if ({{ module }}.modifiable){ - {{ module }}.controls.push(new OpenLayers.Control.ModifyFeature(lyr, {'displayClass': 'olControlModifyFeature'})); - } -}; -{{ module }}.init = function(){ - {% block map_options %}// The options hash, w/ zoom, resolution, and projection settings. - var options = { -{% autoescape off %}{% for item in map_options.items %} '{{ item.0 }}' : {{ item.1 }}{% if not forloop.last %},{% endif %} -{% endfor %}{% endautoescape %} };{% endblock %} - // The admin map for this geometry field. - {% block map_creation %} - {{ module }}.map = new OpenLayers.Map('{{ id }}_map', options); - // Base Layer - {{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS("{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'{{ wms_options|safe }}});{% endblock %} - {{ module }}.map.addLayer({{ module }}.layers.base); - {% endblock %} - {% block extra_layers %}{% endblock %} - {% if is_linestring %}OpenLayers.Feature.Vector.style["default"]["strokeWidth"] = 3; // Default too thin for linestrings. {% endif %} - {{ module }}.layers.vector = new OpenLayers.Layer.Vector(" {{ field_name }}"); - {{ module }}.map.addLayer({{ module }}.layers.vector); - // Read WKT from the text field. - var wkt = document.getElementById('{{ id }}').value; - if (wkt){ - // After reading into geometry, immediately write back to - // WKT ', - output, - ) - - def test_olwidget_invalid_string(self): - geoadmin = site._registry[City] - form = geoadmin.get_changelist_form(None)({"point": "INVALID()"}) - with self.assertLogs("django.contrib.gis", "ERROR") as cm: - output = str(form["point"]) - self.assertInHTML( - '', - output, - ) - self.assertEqual(len(cm.records), 1) - self.assertEqual( - cm.records[0].getMessage(), - "Error creating geometry from value 'INVALID()' (String input " - "unrecognized as WKT EWKT, and HEXEWKB.)", - ) - - -class DeprecationTests(SimpleTestCase): - def test_warning(self): - class DeprecatedOSMGeoAdmin(admin.OSMGeoAdmin): - pass - - class DeprecatedGeoModelAdmin(admin.GeoModelAdmin): - pass - - msg = ( - "django.contrib.gis.admin.GeoModelAdmin and OSMGeoAdmin are " - "deprecated in favor of django.contrib.admin.ModelAdmin and " - "django.contrib.gis.admin.GISModelAdmin." - ) - with self.assertRaisesMessage(RemovedInDjango50Warning, msg): - DeprecatedOSMGeoAdmin(City, site) - with self.assertRaisesMessage(RemovedInDjango50Warning, msg): - DeprecatedGeoModelAdmin(City, site) - - def test_openlayerswidget_warning(self): - msg = "django.contrib.gis.admin.OpenLayersWidget is deprecated." - with self.assertRaisesMessage(RemovedInDjango50Warning, msg): - admin.OpenLayersWidget() diff --git a/tests/gis_tests/geoadmin_deprecated/urls.py b/tests/gis_tests/geoadmin_deprecated/urls.py deleted file mode 100644 index ce237dbfd1..0000000000 --- a/tests/gis_tests/geoadmin_deprecated/urls.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.contrib import admin -from django.urls import include, path - -urlpatterns = [ - path("admin/", include(admin.site.urls)), -]