diff options
Diffstat (limited to 'lib/python2.7/site-packages/django/contrib/gis/forms')
3 files changed, 262 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/django/contrib/gis/forms/__init__.py b/lib/python2.7/site-packages/django/contrib/gis/forms/__init__.py new file mode 100644 index 0000000..93a2d38 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/gis/forms/__init__.py @@ -0,0 +1,5 @@ +from django.forms import * +from .fields import (GeometryField, GeometryCollectionField, PointField, + MultiPointField, LineStringField, MultiLineStringField, PolygonField, + MultiPolygonField) +from .widgets import BaseGeometryWidget, OpenLayersWidget, OSMWidget diff --git a/lib/python2.7/site-packages/django/contrib/gis/forms/fields.py b/lib/python2.7/site-packages/django/contrib/gis/forms/fields.py new file mode 100644 index 0000000..b1c0308 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/gis/forms/fields.py @@ -0,0 +1,137 @@ +from __future__ import unicode_literals + +import warnings + +from django import forms +from django.utils import six +from django.utils.translation import ugettext_lazy as _ + +# While this couples the geographic forms to the GEOS library, +# it decouples from database (by not importing SpatialBackend). +from django.contrib.gis.geos import GEOSException, GEOSGeometry, fromstr +from .widgets import OpenLayersWidget + + +class GeometryField(forms.Field): + """ + This is the basic form field for a Geometry. Any textual input that is + accepted by GEOSGeometry is accepted by this form. By default, + this includes WKT, HEXEWKB, WKB (in a buffer), and GeoJSON. + """ + widget = OpenLayersWidget + geom_type = 'GEOMETRY' + + default_error_messages = { + 'required' : _('No geometry value provided.'), + 'invalid_geom' : _('Invalid geometry value.'), + 'invalid_geom_type' : _('Invalid geometry type.'), + 'transform_error' : _('An error occurred when transforming the geometry ' + 'to the SRID of the geometry form field.'), + } + + def __init__(self, **kwargs): + # Pop out attributes from the database field, or use sensible + # defaults (e.g., allow None). + self.srid = kwargs.pop('srid', None) + self.geom_type = kwargs.pop('geom_type', self.geom_type) + if 'null' in kwargs: + kwargs.pop('null', True) + warnings.warn("Passing 'null' keyword argument to GeometryField is deprecated.", + DeprecationWarning, stacklevel=2) + super(GeometryField, self).__init__(**kwargs) + self.widget.attrs['geom_type'] = self.geom_type + + def to_python(self, value): + """ + Transforms the value to a Geometry object. + """ + if value in self.empty_values: + return None + + if not isinstance(value, GEOSGeometry): + try: + value = GEOSGeometry(value) + except (GEOSException, ValueError, TypeError): + raise forms.ValidationError(self.error_messages['invalid_geom'], code='invalid_geom') + + # Try to set the srid + if not value.srid: + try: + value.srid = self.widget.map_srid + except AttributeError: + if self.srid: + value.srid = self.srid + return value + + def clean(self, value): + """ + Validates that the input value can be converted to a Geometry + object (which is returned). A ValidationError is raised if + the value cannot be instantiated as a Geometry. + """ + geom = super(GeometryField, self).clean(value) + if geom is None: + return geom + + # Ensuring that the geometry is of the correct type (indicated + # using the OGC string label). + if str(geom.geom_type).upper() != self.geom_type and not self.geom_type == 'GEOMETRY': + raise forms.ValidationError(self.error_messages['invalid_geom_type'], code='invalid_geom_type') + + # Transforming the geometry if the SRID was set. + if self.srid and self.srid != -1 and self.srid != geom.srid: + try: + geom.transform(self.srid) + except: + raise forms.ValidationError( + self.error_messages['transform_error'], code='transform_error') + + return geom + + def _has_changed(self, initial, data): + """ Compare geographic value of data with its initial value. """ + + try: + data = self.to_python(data) + initial = self.to_python(initial) + except ValidationError: + return True + + # Only do a geographic comparison if both values are available + if initial and data: + data.transform(initial.srid) + # If the initial value was not added by the browser, the geometry + # provided may be slightly different, the first time it is saved. + # The comparison is done with a very low tolerance. + return not initial.equals_exact(data, tolerance=0.000001) + else: + # Check for change of state of existence + return bool(initial) != bool(data) + + +class GeometryCollectionField(GeometryField): + geom_type = 'GEOMETRYCOLLECTION' + + +class PointField(GeometryField): + geom_type = 'POINT' + + +class MultiPointField(GeometryField): + geom_type = 'MULTIPOINT' + + +class LineStringField(GeometryField): + geom_type = 'LINESTRING' + + +class MultiLineStringField(GeometryField): + geom_type = 'MULTILINESTRING' + + +class PolygonField(GeometryField): + geom_type = 'POLYGON' + + +class MultiPolygonField(GeometryField): + geom_type = 'MULTIPOLYGON' diff --git a/lib/python2.7/site-packages/django/contrib/gis/forms/widgets.py b/lib/python2.7/site-packages/django/contrib/gis/forms/widgets.py new file mode 100644 index 0000000..909684e --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/gis/forms/widgets.py @@ -0,0 +1,120 @@ +from __future__ import unicode_literals + +import logging + +from django.conf import settings +from django.contrib.gis import gdal +from django.contrib.gis.geos import GEOSGeometry, GEOSException +from django.forms.widgets import Widget +from django.template import loader +from django.utils import six +from django.utils import translation + +logger = logging.getLogger('django.contrib.gis') + + +class BaseGeometryWidget(Widget): + """ + The base class for rich geometry widgets. + Renders a map using the WKT of the geometry. + """ + geom_type = 'GEOMETRY' + map_srid = 4326 + map_width = 600 + map_height = 400 + display_raw = False + + supports_3d = False + template_name = '' # set on subclasses + + def __init__(self, attrs=None): + self.attrs = {} + for key in ('geom_type', 'map_srid', 'map_width', 'map_height', 'display_raw'): + self.attrs[key] = getattr(self, key) + if attrs: + self.attrs.update(attrs) + + def serialize(self, value): + return value.wkt if value else '' + + def deserialize(self, value): + try: + return GEOSGeometry(value, self.map_srid) + except (GEOSException, ValueError) as err: + logger.error( + "Error creating geometry from value '%s' (%s)" % ( + value, err) + ) + return None + + def render(self, name, value, attrs=None): + # If a string reaches here (via a validation error on another + # field) then just reconstruct the Geometry. + if isinstance(value, six.string_types): + value = self.deserialize(value) + + if value: + # Check that srid of value and map match + if value.srid != self.map_srid: + try: + ogr = value.ogr + ogr.transform(self.map_srid) + value = ogr + except gdal.OGRException as err: + logger.error( + "Error transforming geometry from srid '%s' to srid '%s' (%s)" % ( + value.srid, self.map_srid, err) + ) + + context = self.build_attrs(attrs, + name=name, + module='geodjango_%s' % name.replace('-','_'), # JS-safe + serialized=self.serialize(value), + geom_type=gdal.OGRGeomType(self.attrs['geom_type']), + STATIC_URL=settings.STATIC_URL, + LANGUAGE_BIDI=translation.get_language_bidi(), + ) + return loader.render_to_string(self.template_name, context) + + +class OpenLayersWidget(BaseGeometryWidget): + template_name = 'gis/openlayers.html' + class Media: + js = ( + 'http://openlayers.org/api/2.11/OpenLayers.js', + 'gis/js/OLMapWidget.js', + ) + + +class OSMWidget(BaseGeometryWidget): + """ + An OpenLayers/OpenStreetMap-based widget. + """ + template_name = 'gis/openlayers-osm.html' + default_lon = 5 + default_lat = 47 + + class Media: + js = ( + 'http://openlayers.org/api/2.11/OpenLayers.js', + 'http://www.openstreetmap.org/openlayers/OpenStreetMap.js', + 'gis/js/OLMapWidget.js', + ) + + @property + def map_srid(self): + # Use the official spherical mercator projection SRID on versions + # of GDAL that support it; otherwise, fallback to 900913. + if gdal.HAS_GDAL and gdal.GDAL_VERSION >= (1, 7): + return 3857 + else: + return 900913 + + def render(self, name, value, attrs=None): + default_attrs = { + 'default_lon': self.default_lon, + 'default_lat': self.default_lat, + } + if attrs: + default_attrs.update(attrs) + return super(OSMWidget, self).render(name, value, default_attrs) |