App Engine Python SDK version 1.7.4 (2)
[gae.git] / python / lib / django_1_4 / django / contrib / gis / utils / ogrinspect.py
blobaa4e2098776aff948b19df88f9099c4c6d10a305
1 """
2 This module is for inspecting OGR data sources and generating either
3 models for GeoDjango and/or mapping dictionaries for use with the
4 `LayerMapping` utility.
6 Author: Travis Pinney, Dane Springmeyer, & Justin Bronn
7 """
8 from itertools import izip
9 # Requires GDAL to use.
10 from django.contrib.gis.gdal import DataSource
11 from django.contrib.gis.gdal.field import OFTDate, OFTDateTime, OFTInteger, OFTReal, OFTString, OFTTime
13 def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
14 """
15 Given a DataSource, generates a dictionary that may be used
16 for invoking the LayerMapping utility.
18 Keyword Arguments:
19 `geom_name` => The name of the geometry field to use for the model.
21 `layer_key` => The key for specifying which layer in the DataSource to use;
22 defaults to 0 (the first layer). May be an integer index or a string
23 identifier for the layer.
25 `multi_geom` => Boolean (default: False) - specify as multigeometry.
26 """
27 if isinstance(data_source, basestring):
28 # Instantiating the DataSource from the string.
29 data_source = DataSource(data_source)
30 elif isinstance(data_source, DataSource):
31 pass
32 else:
33 raise TypeError('Data source parameter must be a string or a DataSource object.')
35 # Creating the dictionary.
36 _mapping = {}
38 # Generating the field name for each field in the layer.
39 for field in data_source[layer_key].fields:
40 mfield = field.lower()
41 if mfield[-1:] == '_': mfield += 'field'
42 _mapping[mfield] = field
43 gtype = data_source[layer_key].geom_type
44 if multi_geom and gtype.num in (1, 2, 3): prefix = 'MULTI'
45 else: prefix = ''
46 _mapping[geom_name] = prefix + str(gtype).upper()
47 return _mapping
49 def ogrinspect(*args, **kwargs):
50 """
51 Given a data source (either a string or a DataSource object) and a string
52 model name this function will generate a GeoDjango model.
54 Usage:
56 >>> from django.contrib.gis.utils import ogrinspect
57 >>> ogrinspect('/path/to/shapefile.shp','NewModel')
59 ...will print model definition to stout
61 or put this in a python script and use to redirect the output to a new
62 model like:
64 $ python generate_model.py > myapp/models.py
66 # generate_model.py
67 from django.contrib.gis.utils import ogrinspect
68 shp_file = 'data/mapping_hacks/world_borders.shp'
69 model_name = 'WorldBorders'
71 print ogrinspect(shp_file, model_name, multi_geom=True, srid=4326,
72 geom_name='shapes', blank=True)
74 Required Arguments
75 `datasource` => string or DataSource object to file pointer
77 `model name` => string of name of new model class to create
79 Optional Keyword Arguments
80 `geom_name` => For specifying the model name for the Geometry Field.
81 Otherwise will default to `geom`
83 `layer_key` => The key for specifying which layer in the DataSource to use;
84 defaults to 0 (the first layer). May be an integer index or a string
85 identifier for the layer.
87 `srid` => The SRID to use for the Geometry Field. If it can be determined,
88 the SRID of the datasource is used.
90 `multi_geom` => Boolean (default: False) - specify as multigeometry.
92 `name_field` => String - specifies a field name to return for the
93 `__unicode__` function (which will be generated if specified).
95 `imports` => Boolean (default: True) - set to False to omit the
96 `from django.contrib.gis.db import models` code from the
97 autogenerated models thus avoiding duplicated imports when building
98 more than one model by batching ogrinspect()
100 `decimal` => Boolean or sequence (default: False). When set to True
101 all generated model fields corresponding to the `OFTReal` type will
102 be `DecimalField` instead of `FloatField`. A sequence of specific
103 field names to generate as `DecimalField` may also be used.
105 `blank` => Boolean or sequence (default: False). When set to True all
106 generated model fields will have `blank=True`. If the user wants to
107 give specific fields to have blank, then a list/tuple of OGR field
108 names may be used.
110 `null` => Boolean (default: False) - When set to True all generated
111 model fields will have `null=True`. If the user wants to specify
112 give specific fields to have null, then a list/tuple of OGR field
113 names may be used.
115 Note: This routine calls the _ogrinspect() helper to do the heavy lifting.
117 return '\n'.join(s for s in _ogrinspect(*args, **kwargs))
119 def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=None,
120 multi_geom=False, name_field=None, imports=True,
121 decimal=False, blank=False, null=False):
123 Helper routine for `ogrinspect` that generates GeoDjango models corresponding
124 to the given data source. See the `ogrinspect` docstring for more details.
126 # Getting the DataSource
127 if isinstance(data_source, str):
128 data_source = DataSource(data_source)
129 elif isinstance(data_source, DataSource):
130 pass
131 else:
132 raise TypeError('Data source parameter must be a string or a DataSource object.')
134 # Getting the layer corresponding to the layer key and getting
135 # a string listing of all OGR fields in the Layer.
136 layer = data_source[layer_key]
137 ogr_fields = layer.fields
139 # Creating lists from the `null`, `blank`, and `decimal`
140 # keyword arguments.
141 def process_kwarg(kwarg):
142 if isinstance(kwarg, (list, tuple)):
143 return [s.lower() for s in kwarg]
144 elif kwarg:
145 return [s.lower() for s in ogr_fields]
146 else:
147 return []
148 null_fields = process_kwarg(null)
149 blank_fields = process_kwarg(blank)
150 decimal_fields = process_kwarg(decimal)
152 # Gets the `null` and `blank` keywords for the given field name.
153 def get_kwargs_str(field_name):
154 kwlist = []
155 if field_name.lower() in null_fields: kwlist.append('null=True')
156 if field_name.lower() in blank_fields: kwlist.append('blank=True')
157 if kwlist: return ', ' + ', '.join(kwlist)
158 else: return ''
160 # For those wishing to disable the imports.
161 if imports:
162 yield '# This is an auto-generated Django model module created by ogrinspect.'
163 yield 'from django.contrib.gis.db import models'
164 yield ''
166 yield 'class %s(models.Model):' % model_name
168 for field_name, width, precision, field_type in izip(ogr_fields, layer.field_widths, layer.field_precisions, layer.field_types):
169 # The model field name.
170 mfield = field_name.lower()
171 if mfield[-1:] == '_': mfield += 'field'
173 # Getting the keyword args string.
174 kwargs_str = get_kwargs_str(field_name)
176 if field_type is OFTReal:
177 # By default OFTReals are mapped to `FloatField`, however, they
178 # may also be mapped to `DecimalField` if specified in the
179 # `decimal` keyword.
180 if field_name.lower() in decimal_fields:
181 yield ' %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)' % (mfield, width, precision, kwargs_str)
182 else:
183 yield ' %s = models.FloatField(%s)' % (mfield, kwargs_str[2:])
184 elif field_type is OFTInteger:
185 yield ' %s = models.IntegerField(%s)' % (mfield, kwargs_str[2:])
186 elif field_type is OFTString:
187 yield ' %s = models.CharField(max_length=%s%s)' % (mfield, width, kwargs_str)
188 elif field_type is OFTDate:
189 yield ' %s = models.DateField(%s)' % (mfield, kwargs_str[2:])
190 elif field_type is OFTDateTime:
191 yield ' %s = models.DateTimeField(%s)' % (mfield, kwargs_str[2:])
192 elif field_type is OFTTime:
193 yield ' %s = models.TimeField(%s)' % (mfield, kwargs_str[2:])
194 else:
195 raise TypeError('Unknown field type %s in %s' % (field_type, mfield))
197 # TODO: Autodetection of multigeometry types (see #7218).
198 gtype = layer.geom_type
199 if multi_geom and gtype.num in (1, 2, 3):
200 geom_field = 'Multi%s' % gtype.django
201 else:
202 geom_field = gtype.django
204 # Setting up the SRID keyword string.
205 if srid is None:
206 if layer.srs is None:
207 srid_str = 'srid=-1'
208 else:
209 srid = layer.srs.srid
210 if srid is None:
211 srid_str = 'srid=-1'
212 elif srid == 4326:
213 # WGS84 is already the default.
214 srid_str = ''
215 else:
216 srid_str = 'srid=%s' % srid
217 else:
218 srid_str = 'srid=%s' % srid
220 yield ' %s = models.%s(%s)' % (geom_name, geom_field, srid_str)
221 yield ' objects = models.GeoManager()'
223 if name_field:
224 yield ''
225 yield ' def __unicode__(self): return self.%s' % name_field