PageRenderTime 27ms CodeModel.GetById 18ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/django/contrib/gis/management/commands/ogrinspect.py

https://code.google.com/p/mango-py/
Python | 122 lines | 107 code | 3 blank | 12 comment | 19 complexity | 5129a33bbacfa4f6e9385ec572f29359 MD5 | raw file
  1import os, sys
  2from optparse import make_option
  3from django.contrib.gis import gdal
  4from django.contrib.gis.management.base import ArgsCommand, CommandError
  5
  6def layer_option(option, opt, value, parser):
  7    """
  8    Callback for `make_option` for the `ogrinspect` `layer_key`
  9    keyword option which may be an integer or a string.
 10    """
 11    try:
 12        dest = int(value)
 13    except ValueError:
 14        dest = value
 15    setattr(parser.values, option.dest, dest)
 16
 17def list_option(option, opt, value, parser):
 18    """
 19    Callback for `make_option` for `ogrinspect` keywords that require
 20    a string list.  If the string is 'True'/'true' then the option 
 21    value will be a boolean instead.
 22    """
 23    if value.lower() == 'true':
 24        dest = True
 25    else:
 26        dest = [s for s in value.split(',')]
 27    setattr(parser.values, option.dest, dest)
 28    
 29class Command(ArgsCommand):
 30    help = ('Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n'
 31            'a GeoDjango model with the given model name. For example:\n'
 32            ' ./manage.py ogrinspect zipcode.shp Zipcode')
 33    args = '[data_source] [model_name]'
 34
 35    option_list = ArgsCommand.option_list + (
 36        make_option('--blank', dest='blank', type='string', action='callback',  
 37                    callback=list_option, default=False,
 38                    help='Use a comma separated list of OGR field names to add '
 39                    'the `blank=True` option to the field definition.  Set with'
 40                    '`true` to apply to all applicable fields.'),
 41        make_option('--decimal', dest='decimal', type='string', action='callback', 
 42                    callback=list_option, default=False,
 43                    help='Use a comma separated list of OGR float fields to '
 44                    'generate `DecimalField` instead of the default '
 45                    '`FloatField`. Set to `true` to apply to all OGR float fields.'),
 46        make_option('--geom-name', dest='geom_name', type='string', default='geom',
 47                    help='Specifies the model name for the Geometry Field '
 48                    '(defaults to `geom`)'),
 49        make_option('--layer', dest='layer_key', type='string', action='callback', 
 50                    callback=layer_option, default=0,
 51                    help='The key for specifying which layer in the OGR data '
 52                    'source to use. Defaults to 0 (the first layer). May be '
 53                    'an integer or a string identifier for the layer.'),
 54        make_option('--multi-geom', action='store_true', dest='multi_geom', default=False,
 55                    help='Treat the geometry in the data source as a geometry collection.'),
 56        make_option('--name-field', dest='name_field',
 57                    help='Specifies a field name to return for the `__unicode__` function.'),
 58        make_option('--no-imports', action='store_false', dest='imports', default=True,
 59                    help='Do not include `from django.contrib.gis.db import models` '
 60                    'statement.'),
 61        make_option('--null', dest='null', type='string', action='callback',  
 62                    callback=list_option, default=False,
 63                    help='Use a comma separated list of OGR field names to add '
 64                    'the `null=True` option to the field definition.  Set with'
 65                    '`true` to apply to all applicable fields.'),
 66        make_option('--srid', dest='srid',
 67                    help='The SRID to use for the Geometry Field.  If it can be '
 68                    'determined, the SRID of the data source is used.'),
 69        make_option('--mapping', action='store_true', dest='mapping',
 70                    help='Generate mapping dictionary for use with `LayerMapping`.')
 71        )
 72
 73    requires_model_validation = False
 74
 75    def handle_args(self, *args, **options):
 76        try:
 77            data_source, model_name = args
 78        except ValueError:
 79            raise CommandError('Invalid arguments, must provide: %s' % self.args)
 80
 81        if not gdal.HAS_GDAL:
 82            raise CommandError('GDAL is required to inspect geospatial data sources.')
 83
 84        # TODO: Support non file-based OGR datasources.
 85        if not os.path.isfile(data_source):
 86            raise CommandError('The given data source cannot be found: "%s"' % data_source)
 87        
 88        # Removing options with `None` values.
 89        options = dict([(k, v) for k, v in options.items() if not v is None])
 90
 91        # Getting the OGR DataSource from the string parameter.
 92        try:
 93            ds = gdal.DataSource(data_source)
 94        except gdal.OGRException, msg:
 95            raise CommandError(msg)
 96
 97        # Whether the user wants to generate the LayerMapping dictionary as well.
 98        show_mapping = options.pop('mapping', False)
 99
100        # Popping the verbosity global option, as it's not accepted by `_ogrinspect`.
101        verbosity = options.pop('verbosity', False)
102
103        # Returning the output of ogrinspect with the given arguments
104        # and options.
105        from django.contrib.gis.utils.ogrinspect import _ogrinspect, mapping
106        output = [s for s in _ogrinspect(ds, model_name, **options)]
107        if show_mapping:
108            # Constructing the keyword arguments for `mapping`, and
109            # calling it on the data source.
110            kwargs = {'geom_name' : options['geom_name'],
111                      'layer_key' : options['layer_key'],
112                      'multi_geom' : options['multi_geom'],
113                      }
114            mapping_dict = mapping(ds, **kwargs)
115            # This extra legwork is so that the dictionary definition comes
116            # out in the same order as the fields in the model definition.
117            rev_mapping = dict([(v, k) for k, v in mapping_dict.items()])
118            output.extend(['', '# Auto-generated `LayerMapping` dictionary for %s model' % model_name, 
119                           '%s_mapping = {' % model_name.lower()])
120            output.extend(["    '%s' : '%s'," % (rev_mapping[ogr_fld], ogr_fld) for ogr_fld in ds[options['layer_key']].fields])
121            output.extend(["    '%s' : '%s'," % (options['geom_name'], mapping_dict[options['geom_name']]), '}'])
122        return '\n'.join(output)