2 from optparse
import make_option
3 from django
.contrib
.gis
import gdal
4 from django
.core
.management
.base
import LabelCommand
, CommandError
6 def layer_option(option
, opt
, value
, parser
):
8 Callback for `make_option` for the `ogrinspect` `layer_key`
9 keyword option which may be an integer or a string.
15 setattr(parser
.values
, option
.dest
, dest
)
17 def list_option(option
, opt
, value
, parser
):
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.
23 if value
.lower() == 'true':
26 dest
= [s
for s
in value
.split(',')]
27 setattr(parser
.values
, option
.dest
, dest
)
29 class Command(LabelCommand
):
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]'
35 option_list
= LabelCommand
.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` '
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`.')
73 requires_model_validation
= False
75 def handle(self
, *args
, **options
):
77 data_source
, model_name
= args
79 raise CommandError('Invalid arguments, must provide: %s' % self
.args
)
82 raise CommandError('GDAL is required to inspect geospatial data sources.')
84 # Removing options with `None` values.
85 options
= dict([(k
, v
) for k
, v
in options
.items() if not v
is None])
87 # Getting the OGR DataSource from the string parameter.
89 ds
= gdal
.DataSource(data_source
)
90 except gdal
.OGRException
, msg
:
91 raise CommandError(msg
)
93 # Whether the user wants to generate the LayerMapping dictionary as well.
94 show_mapping
= options
.pop('mapping', False)
96 # Getting rid of settings that `_ogrinspect` doesn't like.
97 verbosity
= options
.pop('verbosity', False)
98 settings
= options
.pop('settings', False)
100 # Returning the output of ogrinspect with the given arguments
102 from django
.contrib
.gis
.utils
.ogrinspect
import _ogrinspect
, mapping
103 output
= [s
for s
in _ogrinspect(ds
, model_name
, **options
)]
105 # Constructing the keyword arguments for `mapping`, and
106 # calling it on the data source.
107 kwargs
= {'geom_name' : options
['geom_name'],
108 'layer_key' : options
['layer_key'],
109 'multi_geom' : options
['multi_geom'],
111 mapping_dict
= mapping(ds
, **kwargs
)
112 # This extra legwork is so that the dictionary definition comes
113 # out in the same order as the fields in the model definition.
114 rev_mapping
= dict([(v
, k
) for k
, v
in mapping_dict
.items()])
115 output
.extend(['', '# Auto-generated `LayerMapping` dictionary for %s model' % model_name
,
116 '%s_mapping = {' % model_name
.lower()])
117 output
.extend([" '%s' : '%s'," % (rev_mapping
[ogr_fld
], ogr_fld
) for ogr_fld
in ds
[options
['layer_key']].fields
])
118 output
.extend([" '%s' : '%s'," % (options
['geom_name'], mapping_dict
[options
['geom_name']]), '}'])
119 return '\n'.join(output
) + '\n'