You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ogrinspect.py 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import argparse
  2. from django.contrib.gis import gdal
  3. from django.core.management.base import BaseCommand, CommandError
  4. from django.utils.inspect import get_func_args
  5. class LayerOptionAction(argparse.Action):
  6. """
  7. Custom argparse action for the `ogrinspect` `layer_key` keyword option
  8. which may be an integer or a string.
  9. """
  10. def __call__(self, parser, namespace, value, option_string=None):
  11. try:
  12. setattr(namespace, self.dest, int(value))
  13. except ValueError:
  14. setattr(namespace, self.dest, value)
  15. class ListOptionAction(argparse.Action):
  16. """
  17. Custom argparse action for `ogrinspect` keywords that require
  18. a string list. If the string is 'True'/'true' then the option
  19. value will be a boolean instead.
  20. """
  21. def __call__(self, parser, namespace, value, option_string=None):
  22. if value.lower() == 'true':
  23. setattr(namespace, self.dest, True)
  24. else:
  25. setattr(namespace, self.dest, value.split(','))
  26. class Command(BaseCommand):
  27. help = (
  28. 'Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n'
  29. 'a GeoDjango model with the given model name. For example:\n'
  30. ' ./manage.py ogrinspect zipcode.shp Zipcode'
  31. )
  32. requires_system_checks = False
  33. def add_arguments(self, parser):
  34. parser.add_argument('data_source', help='Path to the data source.')
  35. parser.add_argument('model_name', help='Name of the model to create.')
  36. parser.add_argument(
  37. '--blank',
  38. action=ListOptionAction, default=False,
  39. help='Use a comma separated list of OGR field names to add '
  40. 'the `blank=True` option to the field definition. Set to `true` '
  41. 'to apply to all applicable fields.',
  42. )
  43. parser.add_argument(
  44. '--decimal',
  45. action=ListOptionAction, default=False,
  46. help='Use a comma separated list of OGR float fields to '
  47. 'generate `DecimalField` instead of the default '
  48. '`FloatField`. Set to `true` to apply to all OGR float fields.',
  49. )
  50. parser.add_argument(
  51. '--geom-name', default='geom',
  52. help='Specifies the model name for the Geometry Field (defaults to `geom`)'
  53. )
  54. parser.add_argument(
  55. '--layer', dest='layer_key',
  56. action=LayerOptionAction, default=0,
  57. help='The key for specifying which layer in the OGR data '
  58. 'source to use. Defaults to 0 (the first layer). May be '
  59. 'an integer or a string identifier for the layer.',
  60. )
  61. parser.add_argument(
  62. '--multi-geom', action='store_true',
  63. help='Treat the geometry in the data source as a geometry collection.',
  64. )
  65. parser.add_argument(
  66. '--name-field',
  67. help='Specifies a field name to return for the __str__() method.',
  68. )
  69. parser.add_argument(
  70. '--no-imports', action='store_false', dest='imports',
  71. help='Do not include `from django.contrib.gis.db import models` statement.',
  72. )
  73. parser.add_argument(
  74. '--null', action=ListOptionAction, default=False,
  75. help='Use a comma separated list of OGR field names to add '
  76. 'the `null=True` option to the field definition. Set to `true` '
  77. 'to apply to all applicable fields.',
  78. )
  79. parser.add_argument(
  80. '--srid',
  81. help='The SRID to use for the Geometry Field. If it can be '
  82. 'determined, the SRID of the data source is used.',
  83. )
  84. parser.add_argument(
  85. '--mapping', action='store_true',
  86. help='Generate mapping dictionary for use with `LayerMapping`.',
  87. )
  88. def handle(self, *args, **options):
  89. data_source, model_name = options.pop('data_source'), options.pop('model_name')
  90. # Getting the OGR DataSource from the string parameter.
  91. try:
  92. ds = gdal.DataSource(data_source)
  93. except gdal.GDALException as msg:
  94. raise CommandError(msg)
  95. # Returning the output of ogrinspect with the given arguments
  96. # and options.
  97. from django.contrib.gis.utils.ogrinspect import _ogrinspect, mapping
  98. # Filter options to params accepted by `_ogrinspect`
  99. ogr_options = {k: v for k, v in options.items()
  100. if k in get_func_args(_ogrinspect) and v is not None}
  101. output = [s for s in _ogrinspect(ds, model_name, **ogr_options)]
  102. if options['mapping']:
  103. # Constructing the keyword arguments for `mapping`, and
  104. # calling it on the data source.
  105. kwargs = {
  106. 'geom_name': options['geom_name'],
  107. 'layer_key': options['layer_key'],
  108. 'multi_geom': options['multi_geom'],
  109. }
  110. mapping_dict = mapping(ds, **kwargs)
  111. # This extra legwork is so that the dictionary definition comes
  112. # out in the same order as the fields in the model definition.
  113. rev_mapping = {v: k for k, v in mapping_dict.items()}
  114. output.extend(['', '', '# Auto-generated `LayerMapping` dictionary for %s model' % model_name,
  115. '%s_mapping = {' % model_name.lower()])
  116. output.extend(" '%s': '%s'," % (
  117. rev_mapping[ogr_fld], ogr_fld) for ogr_fld in ds[options['layer_key']].fields
  118. )
  119. output.extend([" '%s': '%s'," % (options['geom_name'], mapping_dict[options['geom_name']]), '}'])
  120. return '\n'.join(output) + '\n'