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
« 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)
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.
23 Keyword Arguments:
24 `geom_name` => The name of the geometry field to use for the model.
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.
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 )
42 # Creating the dictionary.
43 _mapping = {}
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
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.
63 Usage:
65 >>> from django.contrib.gis.utils import ogrinspect
66 >>> ogrinspect('/path/to/shapefile.shp','NewModel')
68 ...will print model definition to stout
70 or put this in a Python script and use to redirect the output to a new
71 model like:
73 $ python generate_model.py > myapp/models.py
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'
80 print(ogrinspect(shp_file, model_name, multi_geom=True, srid=4326,
81 geom_name='shapes', blank=True))
83 Required Arguments
84 `datasource` => string or DataSource object to file pointer
86 `model name` => string of name of new model class to create
88 Optional Keyword Arguments
89 `geom_name` => For specifying the model name for the Geometry Field.
90 Otherwise will default to `geom`
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.
96 `srid` => The SRID to use for the Geometry Field. If it can be determined,
97 the SRID of the datasource is used.
99 `multi_geom` => Boolean (default: False) - specify as multigeometry.
101 `name_field` => String - specifies a field name to return for the
102 __str__() method (which will be generated if specified).
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()
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.
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.
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.
124 Note: Call the _ogrinspect() helper to do the heavy lifting.
125 """
126 return "\n".join(_ogrinspect(*args, **kwargs))
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 )
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
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 []
171 null_fields = process_kwarg(null)
172 blank_fields = process_kwarg(blank)
173 decimal_fields = process_kwarg(decimal)
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 ""
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 ""
194 yield "class %s(models.Model):" % model_name
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"
204 # Getting the keyword args string.
205 kwargs_str = get_kwargs_str(field_name)
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))
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
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
263 yield " %s = models.%s(%s)" % (geom_name, geom_field, srid_str)
265 if name_field:
266 yield ""
267 yield " def __str__(self): return self.%s" % name_field