PageRenderTime 28ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

/django/contrib/gis/utils/ogrinspect.py

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