33
33
import warnings
34
34
import json
35
35
36
+ from distutils .version import LooseVersion
37
+ from django import get_version
36
38
from django .conf import settings
37
- from django .contrib . gis import gdal
39
+ from django .core . exceptions import ImproperlyConfigured
38
40
from django .forms .widgets import Widget
39
41
from django .template import loader
40
42
from django .utils import six
45
47
46
48
try :
47
49
from django .contrib .gis .geos import GEOSGeometry
48
- except ImportError :
50
+ except ( ImportError , ImproperlyConfigured ) :
49
51
from .nogeos import GEOSGeometry
50
52
51
53
try :
52
54
from django .contrib .gis .geos import GEOSException
53
- except ImportError :
55
+ except ( ImportError , ImproperlyConfigured ) :
54
56
from .nogeos import GEOSException
55
57
58
+ try :
59
+ from django .contrib .gis .gdal import OGRException
60
+ except (ImportError , ImproperlyConfigured ):
61
+ from .nogeos import OGRException
62
+
63
+ try :
64
+ from django .contrib .gis .gdal import OGRGeomType
65
+ except (ImportError , ImproperlyConfigured ):
66
+ class OGRGeomType :
67
+ """
68
+ Encapsulate OGR Geometry Types.
69
+ Taken from Django GitHub repository:
70
+ https://github.com/django/django/commit/5411821e3b8d1427ee63a5914aed1088c04cc1ed
71
+ """
72
+
73
+ wkb25bit = - 2147483648
74
+
75
+ # Dictionary of acceptable OGRwkbGeometryType s and their string names.
76
+ _types = {0 : 'Unknown' ,
77
+ 1 : 'Point' ,
78
+ 2 : 'LineString' ,
79
+ 3 : 'Polygon' ,
80
+ 4 : 'MultiPoint' ,
81
+ 5 : 'MultiLineString' ,
82
+ 6 : 'MultiPolygon' ,
83
+ 7 : 'GeometryCollection' ,
84
+ 100 : 'None' ,
85
+ 101 : 'LinearRing' ,
86
+ 102 : 'PointZ' ,
87
+ 1 + wkb25bit : 'Point25D' ,
88
+ 2 + wkb25bit : 'LineString25D' ,
89
+ 3 + wkb25bit : 'Polygon25D' ,
90
+ 4 + wkb25bit : 'MultiPoint25D' ,
91
+ 5 + wkb25bit : 'MultiLineString25D' ,
92
+ 6 + wkb25bit : 'MultiPolygon25D' ,
93
+ 7 + wkb25bit : 'GeometryCollection25D' ,
94
+ }
95
+ # Reverse type dictionary, keyed by lower-case of the name.
96
+ _str_types = {v .lower (): k for k , v in _types .items ()}
97
+
98
+ def __init__ (self , type_input ):
99
+ "Figure out the correct OGR Type based upon the input."
100
+ if isinstance (type_input , OGRGeomType ):
101
+ num = type_input .num
102
+ elif isinstance (type_input , str ):
103
+ type_input = type_input .lower ()
104
+ if type_input == 'geometry' :
105
+ type_input = 'unknown'
106
+ num = self ._str_types .get (type_input )
107
+ if num is None :
108
+ raise GEOSException ('Invalid OGR String Type "%s"' % type_input )
109
+ elif isinstance (type_input , int ):
110
+ if type_input not in self ._types :
111
+ raise GEOSException ('Invalid OGR Integer Type: %d' % type_input )
112
+ num = type_input
113
+ else :
114
+ raise TypeError ('Invalid OGR input type given.' )
115
+
116
+ # Setting the OGR geometry type number.
117
+ self .num = num
118
+
119
+ def __str__ (self ):
120
+ "Return the value of the name property."
121
+ return self .name
122
+
123
+ def __eq__ (self , other ):
124
+ """
125
+ Do an equivalence test on the OGR type with the given
126
+ other OGRGeomType, the short-hand string, or the integer.
127
+ """
128
+ if isinstance (other , OGRGeomType ):
129
+ return self .num == other .num
130
+ elif isinstance (other , str ):
131
+ return self .name .lower () == other .lower ()
132
+ elif isinstance (other , int ):
133
+ return self .num == other
134
+ else :
135
+ return False
136
+
137
+ @property
138
+ def name (self ):
139
+ "Return a short-hand string form of the OGR Geometry type."
140
+ return self ._types [self .num ]
141
+
142
+ @property
143
+ def django (self ):
144
+ "Return the Django GeometryField for this OGR Type."
145
+ s = self .name .replace ('25D' , '' )
146
+ if s in ('LinearRing' , 'None' ):
147
+ return None
148
+ elif s == 'Unknown' :
149
+ s = 'Geometry'
150
+ elif s == 'PointZ' :
151
+ s = 'Point'
152
+ return s + 'Field'
153
+
154
+ def to_multi (self ):
155
+ """
156
+ Transform Point, LineString, Polygon, and their 25D equivalents
157
+ to their Multi... counterpart.
158
+ """
159
+ if self .name .startswith (('Point' , 'LineString' , 'Polygon' )):
160
+ self .num += 3
161
+
56
162
logger = logging .getLogger ('django.contrib.gis' )
57
163
58
164
59
165
class BaseGeometryWidget (Widget ):
60
166
"""
61
167
The base class for rich geometry widgets.
62
- Renders a map using the WKT of the geometry.
168
+ Render a map using the WKT of the geometry.
169
+ Adapted from:
170
+ https://github.com/django/django/commit/a7975260b50282b934c78c8e51846d103636ba04
63
171
"""
64
172
geom_type = 'GEOMETRY'
65
173
map_srid = 4326
@@ -82,45 +190,81 @@ def serialize(self, value):
82
190
83
191
def deserialize (self , value ):
84
192
try :
193
+ # To allow older versions of django-leaflet to work,
194
+ # self.map_srid is also returned (unlike the imported Django class)
85
195
return GEOSGeometry (value , self .map_srid )
86
196
except (GEOSException , ValueError ) as err :
87
- logger .error (
88
- "Error creating geometry from value '%s' (%s)" % (value , err )
89
- )
197
+ logger .error ("Error creating geometry from value '%s' (%s)" , value , err )
90
198
return None
91
199
92
- def render (self , name , value , attrs = None ):
93
- # If a string reaches here (via a validation error on another
94
- # field) then just reconstruct the Geometry.
95
- if isinstance (value , six .string_types ):
96
- value = self .deserialize (value )
97
-
98
- if isinstance (value , dict ):
99
- value = GEOSGeometry (json .dumps (value ), srid = self .map_srid )
100
-
101
- if value :
102
- # Check that srid of value and map match
103
- if value .srid != self .map_srid :
104
- try :
105
- ogr = value .ogr
106
- ogr .transform (self .map_srid )
107
- value = ogr
108
- except gdal .OGRException as err :
109
- logger .error (
110
- "Error transforming geometry from srid '%s' to srid "
111
- "'%s' (%s)" % (value .srid , self .map_srid , err )
112
- )
113
-
114
- context = self .build_attrs (
115
- attrs ,
116
- name = name ,
117
- module = 'geodjango_%s' % name .replace ('-' , '_' ), # JS-safe
118
- serialized = self .serialize (value ),
119
- geom_type = gdal .OGRGeomType (self .attrs ['geom_type' ]),
120
- STATIC_URL = settings .STATIC_URL ,
121
- LANGUAGE_BIDI = translation .get_language_bidi (),
122
- )
123
- return loader .render_to_string (self .template_name , context )
200
+ if LooseVersion (get_version ()) >= LooseVersion ('1.11' ):
201
+ def get_context (self , name , value , attrs ):
202
+ context = super ().get_context (name , value , attrs )
203
+ # If a string reaches here (via a validation error on another
204
+ # field) then just reconstruct the Geometry.
205
+ if value and isinstance (value , str ):
206
+ value = self .deserialize (value )
207
+
208
+ if value :
209
+ # Check that srid of value and map match
210
+ if value .srid and value .srid != self .map_srid :
211
+ try :
212
+ ogr = value .ogr
213
+ ogr .transform (self .map_srid )
214
+ value = ogr
215
+ except OGRException as err :
216
+ logger .error (
217
+ "Error transforming geometry from srid '%s' to srid '%s' (%s)" ,
218
+ value .srid , self .map_srid , err
219
+ )
220
+
221
+ if attrs is None :
222
+ attrs = {}
223
+
224
+ build_attrs_kwargs = {
225
+ 'name' : name ,
226
+ 'module' : 'geodjango_%s' % name .replace ('-' , '_' ), # JS-safe
227
+ 'serialized' : self .serialize (value ),
228
+ 'geom_type' : OGRGeomType (self .attrs ['geom_type' ]),
229
+ 'STATIC_URL' : settings .STATIC_URL ,
230
+ 'LANGUAGE_BIDI' : translation .get_language_bidi (),
231
+ }
232
+ build_attrs_kwargs .update (attrs )
233
+ context .update (self .build_attrs (self .attrs , build_attrs_kwargs ))
234
+ return context
235
+ else :
236
+ def render (self , name , value , attrs = None ):
237
+ # If a string reaches here (via a validation error on another
238
+ # field) then just reconstruct the Geometry.
239
+ if isinstance (value , six .string_types ):
240
+ value = self .deserialize (value )
241
+
242
+ if isinstance (value , dict ):
243
+ value = GEOSGeometry (json .dumps (value ), srid = self .map_srid )
244
+
245
+ if value :
246
+ # Check that srid of value and map match
247
+ if value .srid != self .map_srid :
248
+ try :
249
+ ogr = value .ogr
250
+ ogr .transform (self .map_srid )
251
+ value = ogr
252
+ except OGRException as err :
253
+ logger .error (
254
+ "Error transforming geometry from srid '%s' to srid "
255
+ "'%s' (%s)" % (value .srid , self .map_srid , err )
256
+ )
257
+
258
+ context = self .build_attrs (
259
+ attrs ,
260
+ name = name ,
261
+ module = 'geodjango_%s' % name .replace ('-' , '_' ), # JS-safe
262
+ serialized = self .serialize (value ),
263
+ geom_type = OGRGeomType (self .attrs ['geom_type' ]),
264
+ STATIC_URL = settings .STATIC_URL ,
265
+ LANGUAGE_BIDI = translation .get_language_bidi (),
266
+ )
267
+ return loader .render_to_string (self .template_name , context )
124
268
125
269
126
270
class GeometryField (forms .Field ):
0 commit comments