2014-06-07 04:39:33 +08:00
|
|
|
import argparse
|
2013-12-31 21:36:45 +08:00
|
|
|
|
2008-08-06 02:13:06 +08:00
|
|
|
from django.contrib.gis import gdal
|
2014-06-07 04:39:33 +08:00
|
|
|
from django.core.management.base import BaseCommand, CommandError
|
2015-06-11 05:24:04 +08:00
|
|
|
from django.utils.inspect import get_func_args
|
2008-08-06 02:13:06 +08:00
|
|
|
|
2013-11-03 04:12:09 +08:00
|
|
|
|
2014-06-07 04:39:33 +08:00
|
|
|
class LayerOptionAction(argparse.Action):
|
2008-08-06 02:13:06 +08:00
|
|
|
"""
|
2014-06-07 04:39:33 +08:00
|
|
|
Custom argparse action for the `ogrinspect` `layer_key` keyword option
|
|
|
|
which may be an integer or a string.
|
2008-08-06 02:13:06 +08:00
|
|
|
"""
|
2014-06-07 04:39:33 +08:00
|
|
|
def __call__(self, parser, namespace, value, option_string=None):
|
|
|
|
try:
|
|
|
|
setattr(namespace, self.dest, int(value))
|
|
|
|
except ValueError:
|
|
|
|
setattr(namespace, self.dest, value)
|
2008-08-06 02:13:06 +08:00
|
|
|
|
2013-11-03 04:12:09 +08:00
|
|
|
|
2014-06-07 04:39:33 +08:00
|
|
|
class ListOptionAction(argparse.Action):
|
2008-08-06 02:13:06 +08:00
|
|
|
"""
|
2014-06-07 04:39:33 +08:00
|
|
|
Custom argparse action for `ogrinspect` keywords that require
|
|
|
|
a string list. If the string is 'True'/'true' then the option
|
2008-08-06 02:13:06 +08:00
|
|
|
value will be a boolean instead.
|
|
|
|
"""
|
2014-06-07 04:39:33 +08:00
|
|
|
def __call__(self, parser, namespace, value, option_string=None):
|
|
|
|
if value.lower() == 'true':
|
|
|
|
setattr(namespace, self.dest, True)
|
|
|
|
else:
|
|
|
|
setattr(namespace, self.dest, value.split(','))
|
2011-09-18 03:54:52 +08:00
|
|
|
|
2013-11-03 04:12:09 +08:00
|
|
|
|
2014-06-07 04:39:33 +08:00
|
|
|
class Command(BaseCommand):
|
2016-03-29 06:33:29 +08:00
|
|
|
help = (
|
|
|
|
'Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n'
|
|
|
|
'a GeoDjango model with the given model name. For example:\n'
|
|
|
|
' ./manage.py ogrinspect zipcode.shp Zipcode'
|
|
|
|
)
|
2008-08-06 02:13:06 +08:00
|
|
|
|
2014-01-20 10:45:21 +08:00
|
|
|
requires_system_checks = False
|
2008-08-06 02:13:06 +08:00
|
|
|
|
2014-06-07 04:39:33 +08:00
|
|
|
def add_arguments(self, parser):
|
|
|
|
parser.add_argument('data_source', help='Path to the data source.')
|
|
|
|
parser.add_argument('model_name', help='Name of the model to create.')
|
2016-03-29 06:33:29 +08:00
|
|
|
parser.add_argument(
|
2018-07-03 05:54:57 +08:00
|
|
|
'--blank',
|
2014-06-07 04:39:33 +08:00
|
|
|
action=ListOptionAction, default=False,
|
|
|
|
help='Use a comma separated list of OGR field names to add '
|
2016-03-29 06:33:29 +08:00
|
|
|
'the `blank=True` option to the field definition. Set to `true` '
|
|
|
|
'to apply to all applicable fields.',
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
2018-07-03 05:54:57 +08:00
|
|
|
'--decimal',
|
2014-06-07 04:39:33 +08:00
|
|
|
action=ListOptionAction, default=False,
|
|
|
|
help='Use a comma separated list of OGR float fields to '
|
2016-03-29 06:33:29 +08:00
|
|
|
'generate `DecimalField` instead of the default '
|
|
|
|
'`FloatField`. Set to `true` to apply to all OGR float fields.',
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
2018-07-03 05:54:57 +08:00
|
|
|
'--geom-name', default='geom',
|
2016-03-29 06:33:29 +08:00
|
|
|
help='Specifies the model name for the Geometry Field (defaults to `geom`)'
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
'--layer', dest='layer_key',
|
2014-06-07 04:39:33 +08:00
|
|
|
action=LayerOptionAction, default=0,
|
|
|
|
help='The key for specifying which layer in the OGR data '
|
2016-03-29 06:33:29 +08:00
|
|
|
'source to use. Defaults to 0 (the first layer). May be '
|
|
|
|
'an integer or a string identifier for the layer.',
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
2018-07-03 05:54:57 +08:00
|
|
|
'--multi-geom', action='store_true',
|
2016-03-29 06:33:29 +08:00
|
|
|
help='Treat the geometry in the data source as a geometry collection.',
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
2018-07-03 05:54:57 +08:00
|
|
|
'--name-field',
|
2017-01-21 05:04:05 +08:00
|
|
|
help='Specifies a field name to return for the __str__() method.',
|
2016-03-29 06:33:29 +08:00
|
|
|
)
|
|
|
|
parser.add_argument(
|
2017-04-02 08:03:56 +08:00
|
|
|
'--no-imports', action='store_false', dest='imports',
|
2016-03-29 06:33:29 +08:00
|
|
|
help='Do not include `from django.contrib.gis.db import models` statement.',
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
2018-07-03 05:54:57 +08:00
|
|
|
'--null', action=ListOptionAction, default=False,
|
2014-06-07 04:39:33 +08:00
|
|
|
help='Use a comma separated list of OGR field names to add '
|
2016-03-29 06:33:29 +08:00
|
|
|
'the `null=True` option to the field definition. Set to `true` '
|
|
|
|
'to apply to all applicable fields.',
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
2018-07-03 05:54:57 +08:00
|
|
|
'--srid',
|
2014-06-07 04:39:33 +08:00
|
|
|
help='The SRID to use for the Geometry Field. If it can be '
|
2016-03-29 06:33:29 +08:00
|
|
|
'determined, the SRID of the data source is used.',
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
2018-07-03 05:54:57 +08:00
|
|
|
'--mapping', action='store_true',
|
2016-03-29 06:33:29 +08:00
|
|
|
help='Generate mapping dictionary for use with `LayerMapping`.',
|
|
|
|
)
|
2008-08-06 02:13:06 +08:00
|
|
|
|
2014-06-07 04:39:33 +08:00
|
|
|
def handle(self, *args, **options):
|
|
|
|
data_source, model_name = options.pop('data_source'), options.pop('model_name')
|
2008-08-06 02:13:06 +08:00
|
|
|
|
|
|
|
# Getting the OGR DataSource from the string parameter.
|
|
|
|
try:
|
|
|
|
ds = gdal.DataSource(data_source)
|
2014-12-18 05:00:05 +08:00
|
|
|
except gdal.GDALException as msg:
|
2008-08-06 02:13:06 +08:00
|
|
|
raise CommandError(msg)
|
|
|
|
|
|
|
|
# Returning the output of ogrinspect with the given arguments
|
|
|
|
# and options.
|
|
|
|
from django.contrib.gis.utils.ogrinspect import _ogrinspect, mapping
|
2013-12-31 21:36:45 +08:00
|
|
|
# Filter options to params accepted by `_ogrinspect`
|
2014-12-07 05:00:09 +08:00
|
|
|
ogr_options = {k: v for k, v in options.items()
|
2015-06-11 05:24:04 +08:00
|
|
|
if k in get_func_args(_ogrinspect) and v is not None}
|
2013-12-31 21:36:45 +08:00
|
|
|
output = [s for s in _ogrinspect(ds, model_name, **ogr_options)]
|
|
|
|
|
|
|
|
if options['mapping']:
|
2008-08-06 02:13:06 +08:00
|
|
|
# Constructing the keyword arguments for `mapping`, and
|
|
|
|
# calling it on the data source.
|
2016-03-29 06:33:29 +08:00
|
|
|
kwargs = {
|
|
|
|
'geom_name': options['geom_name'],
|
|
|
|
'layer_key': options['layer_key'],
|
|
|
|
'multi_geom': options['multi_geom'],
|
|
|
|
}
|
2008-08-06 02:13:06 +08:00
|
|
|
mapping_dict = mapping(ds, **kwargs)
|
|
|
|
# This extra legwork is so that the dictionary definition comes
|
|
|
|
# out in the same order as the fields in the model definition.
|
2014-12-07 05:00:09 +08:00
|
|
|
rev_mapping = {v: k for k, v in mapping_dict.items()}
|
2017-09-19 17:41:40 +08:00
|
|
|
output.extend(['', '', '# Auto-generated `LayerMapping` dictionary for %s model' % model_name,
|
2008-08-06 02:13:06 +08:00
|
|
|
'%s_mapping = {' % model_name.lower()])
|
2017-09-19 17:41:40 +08:00
|
|
|
output.extend(" '%s': '%s'," % (
|
2014-09-04 20:15:09 +08:00
|
|
|
rev_mapping[ogr_fld], ogr_fld) for ogr_fld in ds[options['layer_key']].fields
|
|
|
|
)
|
2017-09-19 17:41:40 +08:00
|
|
|
output.extend([" '%s': '%s'," % (options['geom_name'], mapping_dict[options['geom_name']]), '}'])
|
2011-09-18 03:54:52 +08:00
|
|
|
return '\n'.join(output) + '\n'
|