Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/contrib/gis/utils/ogrinspect.py: 1%

93 statements  

« prev     ^ index     » next       coverage.py v7.0.5, created at 2023-01-17 06:13 +0000

1""" 

2This module is for inspecting OGR data sources and generating either 

3models for GeoDjango and/or mapping dictionaries for use with the 

4`LayerMapping` utility. 

5""" 

6from django.contrib.gis.gdal import DataSource 

7from django.contrib.gis.gdal.field import ( 

8 OFTDate, 

9 OFTDateTime, 

10 OFTInteger, 

11 OFTInteger64, 

12 OFTReal, 

13 OFTString, 

14 OFTTime, 

15) 

16 

17 

18def mapping(data_source, geom_name="geom", layer_key=0, multi_geom=False): 

19 """ 

20 Given a DataSource, generate a dictionary that may be used 

21 for invoking the LayerMapping utility. 

22 

23 Keyword Arguments: 

24 `geom_name` => The name of the geometry field to use for the model. 

25 

26 `layer_key` => The key for specifying which layer in the DataSource to use; 

27 defaults to 0 (the first layer). May be an integer index or a string 

28 identifier for the layer. 

29 

30 `multi_geom` => Boolean (default: False) - specify as multigeometry. 

31 """ 

32 if isinstance(data_source, str): 

33 # Instantiating the DataSource from the string. 

34 data_source = DataSource(data_source) 

35 elif isinstance(data_source, DataSource): 

36 pass 

37 else: 

38 raise TypeError( 

39 "Data source parameter must be a string or a DataSource object." 

40 ) 

41 

42 # Creating the dictionary. 

43 _mapping = {} 

44 

45 # Generating the field name for each field in the layer. 

46 for field in data_source[layer_key].fields: 

47 mfield = field.lower() 

48 if mfield[-1:] == "_": 

49 mfield += "field" 

50 _mapping[mfield] = field 

51 gtype = data_source[layer_key].geom_type 

52 if multi_geom: 

53 gtype.to_multi() 

54 _mapping[geom_name] = str(gtype).upper() 

55 return _mapping 

56 

57 

58def ogrinspect(*args, **kwargs): 

59 """ 

60 Given a data source (either a string or a DataSource object) and a string 

61 model name this function will generate a GeoDjango model. 

62 

63 Usage: 

64 

65 >>> from django.contrib.gis.utils import ogrinspect 

66 >>> ogrinspect('/path/to/shapefile.shp','NewModel') 

67 

68 ...will print model definition to stout 

69 

70 or put this in a Python script and use to redirect the output to a new 

71 model like: 

72 

73 $ python generate_model.py > myapp/models.py 

74 

75 # generate_model.py 

76 from django.contrib.gis.utils import ogrinspect 

77 shp_file = 'data/mapping_hacks/world_borders.shp' 

78 model_name = 'WorldBorders' 

79 

80 print(ogrinspect(shp_file, model_name, multi_geom=True, srid=4326, 

81 geom_name='shapes', blank=True)) 

82 

83 Required Arguments 

84 `datasource` => string or DataSource object to file pointer 

85 

86 `model name` => string of name of new model class to create 

87 

88 Optional Keyword Arguments 

89 `geom_name` => For specifying the model name for the Geometry Field. 

90 Otherwise will default to `geom` 

91 

92 `layer_key` => The key for specifying which layer in the DataSource to use; 

93 defaults to 0 (the first layer). May be an integer index or a string 

94 identifier for the layer. 

95 

96 `srid` => The SRID to use for the Geometry Field. If it can be determined, 

97 the SRID of the datasource is used. 

98 

99 `multi_geom` => Boolean (default: False) - specify as multigeometry. 

100 

101 `name_field` => String - specifies a field name to return for the 

102 __str__() method (which will be generated if specified). 

103 

104 `imports` => Boolean (default: True) - set to False to omit the 

105 `from django.contrib.gis.db import models` code from the 

106 autogenerated models thus avoiding duplicated imports when building 

107 more than one model by batching ogrinspect() 

108 

109 `decimal` => Boolean or sequence (default: False). When set to True 

110 all generated model fields corresponding to the `OFTReal` type will 

111 be `DecimalField` instead of `FloatField`. A sequence of specific 

112 field names to generate as `DecimalField` may also be used. 

113 

114 `blank` => Boolean or sequence (default: False). When set to True all 

115 generated model fields will have `blank=True`. If the user wants to 

116 give specific fields to have blank, then a list/tuple of OGR field 

117 names may be used. 

118 

119 `null` => Boolean (default: False) - When set to True all generated 

120 model fields will have `null=True`. If the user wants to specify 

121 give specific fields to have null, then a list/tuple of OGR field 

122 names may be used. 

123 

124 Note: Call the _ogrinspect() helper to do the heavy lifting. 

125 """ 

126 return "\n".join(_ogrinspect(*args, **kwargs)) 

127 

128 

129def _ogrinspect( 

130 data_source, 

131 model_name, 

132 geom_name="geom", 

133 layer_key=0, 

134 srid=None, 

135 multi_geom=False, 

136 name_field=None, 

137 imports=True, 

138 decimal=False, 

139 blank=False, 

140 null=False, 

141): 

142 """ 

143 Helper routine for `ogrinspect` that generates GeoDjango models corresponding 

144 to the given data source. See the `ogrinspect` docstring for more details. 

145 """ 

146 # Getting the DataSource 

147 if isinstance(data_source, str): 

148 data_source = DataSource(data_source) 

149 elif isinstance(data_source, DataSource): 

150 pass 

151 else: 

152 raise TypeError( 

153 "Data source parameter must be a string or a DataSource object." 

154 ) 

155 

156 # Getting the layer corresponding to the layer key and getting 

157 # a string listing of all OGR fields in the Layer. 

158 layer = data_source[layer_key] 

159 ogr_fields = layer.fields 

160 

161 # Creating lists from the `null`, `blank`, and `decimal` 

162 # keyword arguments. 

163 def process_kwarg(kwarg): 

164 if isinstance(kwarg, (list, tuple)): 

165 return [s.lower() for s in kwarg] 

166 elif kwarg: 

167 return [s.lower() for s in ogr_fields] 

168 else: 

169 return [] 

170 

171 null_fields = process_kwarg(null) 

172 blank_fields = process_kwarg(blank) 

173 decimal_fields = process_kwarg(decimal) 

174 

175 # Gets the `null` and `blank` keywords for the given field name. 

176 def get_kwargs_str(field_name): 

177 kwlist = [] 

178 if field_name.lower() in null_fields: 

179 kwlist.append("null=True") 

180 if field_name.lower() in blank_fields: 

181 kwlist.append("blank=True") 

182 if kwlist: 

183 return ", " + ", ".join(kwlist) 

184 else: 

185 return "" 

186 

187 # For those wishing to disable the imports. 

188 if imports: 

189 yield "# This is an auto-generated Django model module created by ogrinspect." 

190 yield "from django.contrib.gis.db import models" 

191 yield "" 

192 yield "" 

193 

194 yield "class %s(models.Model):" % model_name 

195 

196 for field_name, width, precision, field_type in zip( 

197 ogr_fields, layer.field_widths, layer.field_precisions, layer.field_types 

198 ): 

199 # The model field name. 

200 mfield = field_name.lower() 

201 if mfield[-1:] == "_": 

202 mfield += "field" 

203 

204 # Getting the keyword args string. 

205 kwargs_str = get_kwargs_str(field_name) 

206 

207 if field_type is OFTReal: 

208 # By default OFTReals are mapped to `FloatField`, however, they 

209 # may also be mapped to `DecimalField` if specified in the 

210 # `decimal` keyword. 

211 if field_name.lower() in decimal_fields: 

212 yield ( 

213 " %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)" 

214 ) % ( 

215 mfield, 

216 width, 

217 precision, 

218 kwargs_str, 

219 ) 

220 else: 

221 yield " %s = models.FloatField(%s)" % (mfield, kwargs_str[2:]) 

222 elif field_type is OFTInteger: 

223 yield " %s = models.IntegerField(%s)" % (mfield, kwargs_str[2:]) 

224 elif field_type is OFTInteger64: 

225 yield " %s = models.BigIntegerField(%s)" % (mfield, kwargs_str[2:]) 

226 elif field_type is OFTString: 

227 yield " %s = models.CharField(max_length=%s%s)" % ( 

228 mfield, 

229 width, 

230 kwargs_str, 

231 ) 

232 elif field_type is OFTDate: 

233 yield " %s = models.DateField(%s)" % (mfield, kwargs_str[2:]) 

234 elif field_type is OFTDateTime: 

235 yield " %s = models.DateTimeField(%s)" % (mfield, kwargs_str[2:]) 

236 elif field_type is OFTTime: 

237 yield " %s = models.TimeField(%s)" % (mfield, kwargs_str[2:]) 

238 else: 

239 raise TypeError("Unknown field type %s in %s" % (field_type, mfield)) 

240 

241 # TODO: Autodetection of multigeometry types (see #7218). 

242 gtype = layer.geom_type 

243 if multi_geom: 

244 gtype.to_multi() 

245 geom_field = gtype.django 

246 

247 # Setting up the SRID keyword string. 

248 if srid is None: 

249 if layer.srs is None: 

250 srid_str = "srid=-1" 

251 else: 

252 srid = layer.srs.srid 

253 if srid is None: 

254 srid_str = "srid=-1" 

255 elif srid == 4326: 

256 # WGS84 is already the default. 

257 srid_str = "" 

258 else: 

259 srid_str = "srid=%s" % srid 

260 else: 

261 srid_str = "srid=%s" % srid 

262 

263 yield " %s = models.%s(%s)" % (geom_name, geom_field, srid_str) 

264 

265 if name_field: 

266 yield "" 

267 yield " def __str__(self): return self.%s" % name_field