Ticket #15277: 15277.4.patch

File 15277.4.patch, 10.7 KB (added by jpaulett, 4 years ago)

Test TimeField by having GDAL inspect a geo database model

  • deleted file django/contrib/gis/management/base.py

    diff --git django/contrib/gis/management/base.py django/contrib/gis/management/base.py
    deleted file mode 100644
    index c998063..0000000
    + -  
    1 from django.core.management.base import BaseCommand, CommandError
    2 
    3 class ArgsCommand(BaseCommand):
    4     """
    5     Command class for commands that take multiple arguments.
    6     """
    7     args = '<arg arg ...>'
    8 
    9     def handle(self, *args, **options):
    10         if not args:
    11             raise CommandError('Must provide the following arguments: %s' % self.args)
    12         return self.handle_args(*args, **options)
    13 
    14     def handle_args(self, *args, **options):
    15         raise NotImplementedError()
  • django/contrib/gis/management/commands/ogrinspect.py

    diff --git django/contrib/gis/management/commands/ogrinspect.py django/contrib/gis/management/commands/ogrinspect.py
    index 13f1c0a..bffb073 100644
     
    11import os
    22from optparse import make_option
    33from django.contrib.gis import gdal
    4 from django.contrib.gis.management.base import ArgsCommand, CommandError
     4from django.core.management.base import LabelCommand, CommandError
    55
    66def layer_option(option, opt, value, parser):
    77    """
    def list_option(option, opt, value, parser): 
    2626        dest = [s for s in value.split(',')]
    2727    setattr(parser.values, option.dest, dest)
    2828   
    29 class Command(ArgsCommand):
     29class Command(LabelCommand):
    3030    help = ('Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n'
    3131            'a GeoDjango model with the given model name. For example:\n'
    3232            ' ./manage.py ogrinspect zipcode.shp Zipcode')
    3333    args = '[data_source] [model_name]'
    3434
    35     option_list = ArgsCommand.option_list + (
     35    option_list = LabelCommand.option_list + (
    3636        make_option('--blank', dest='blank', type='string', action='callback', 
    3737                    callback=list_option, default=False,
    3838                    help='Use a comma separated list of OGR field names to add '
    class Command(ArgsCommand): 
    7272
    7373    requires_model_validation = False
    7474
    75     def handle_args(self, *args, **options):
     75    def handle(self, *args, **options):
    7676        try:
    7777            data_source, model_name = args
    7878        except ValueError:
    class Command(ArgsCommand): 
    8181        if not gdal.HAS_GDAL:
    8282            raise CommandError('GDAL is required to inspect geospatial data sources.')
    8383
    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        
    8884        # Removing options with `None` values.
    8985        options = dict([(k, v) for k, v in options.items() if not v is None])
    9086
    class Command(ArgsCommand): 
    9793        # Whether the user wants to generate the LayerMapping dictionary as well.
    9894        show_mapping = options.pop('mapping', False)
    9995
    100         # Popping the verbosity global option, as it's not accepted by `_ogrinspect`.
     96        # Getting rid of settings that `_ogrinspect` doesn't like.
    10197        verbosity = options.pop('verbosity', False)
     98        settings = options.pop('settings', False)
    10299
    103100        # Returning the output of ogrinspect with the given arguments
    104101        # and options.
    class Command(ArgsCommand): 
    119116                           '%s_mapping = {' % model_name.lower()])
    120117            output.extend(["    '%s' : '%s'," % (rev_mapping[ogr_fld], ogr_fld) for ogr_fld in ds[options['layer_key']].fields])
    121118            output.extend(["    '%s' : '%s'," % (options['geom_name'], mapping_dict[options['geom_name']]), '}'])
    122         return '\n'.join(output)
     119        return '\n'.join(output) + '\n'
  • django/contrib/gis/tests/__init__.py

    diff --git django/contrib/gis/tests/__init__.py django/contrib/gis/tests/__init__.py
    index 3d04242..75919b2 100644
    def geo_apps(namespace=True, runtests=False): 
    1717    from django.contrib.gis.geos import GEOS_PREPARE
    1818    from django.contrib.gis.gdal import HAS_GDAL
    1919
    20     apps = ['geoapp', 'relatedapp']
     20    apps = ['geoapp', 'relatedapp', 'inspectapp']
    2121
    2222    # No distance queries on MySQL.
    2323    if not connection.ops.mysql:
  • new file django/contrib/gis/tests/inspectapp/models.py

    diff --git django/contrib/gis/tests/inspectapp/__init__.py django/contrib/gis/tests/inspectapp/__init__.py
    new file mode 100644
    index 0000000..e69de29
    diff --git django/contrib/gis/tests/inspectapp/models.py django/contrib/gis/tests/inspectapp/models.py
    new file mode 100644
    index 0000000..0f1b0d4
    - +  
     1from django.contrib.gis.db import models
     2
     3class AllOGRFields(models.Model):
     4    f_decimal = models.FloatField()
     5    f_float = models.FloatField()
     6    f_int = models.IntegerField()
     7    f_char = models.CharField(max_length=10)
     8    f_date = models.DateField()
     9    f_datetime = models.DateTimeField()
     10    f_time = models.TimeField()
     11    geom = models.PolygonField()
     12
     13    objects = models.GeoManager()
  • new file django/contrib/gis/tests/inspectapp/tests.py

    diff --git django/contrib/gis/tests/inspectapp/tests.py django/contrib/gis/tests/inspectapp/tests.py
    new file mode 100644
    index 0000000..c747e0a
    - +  
     1import os
     2from django.contrib.gis.geometry.test_data import TEST_DATA
     3from django.contrib.gis.tests.utils import no_spatialite
     4from django.contrib.gis.utils.ogrinspect import ogrinspect
     5from django.db import connections
     6from django.utils import unittest
     7from django.contrib.gis.tests.utils import (
     8    no_mysql, no_oracle, no_spatialite,
     9    mysql, oracle, postgis, spatialite)
     10from models import AllOGRFields
     11
     12
     13class OGRInspectTest(unittest.TestCase):
     14    def test_poly(self):
     15        shp_file = os.path.join(TEST_DATA, 'test_poly', 'test_poly.shp')
     16        model_def = ogrinspect(shp_file, 'MyModel')
     17
     18        expected = [
     19            '# This is an auto-generated Django model module created by ogrinspect.',
     20            'from django.contrib.gis.db import models',
     21            '',
     22            'class MyModel(models.Model):',
     23            '    float = models.FloatField()',
     24            '    int = models.FloatField()',
     25            '    str = models.CharField(max_length=80)',
     26            '    geom = models.PolygonField(srid=-1)',
     27            '    objects = models.GeoManager()',
     28        ]
     29
     30        self.assertEqual(model_def, '\n'.join(expected))
     31
     32    def test_date_field(self):
     33        shp_file = os.path.join(TEST_DATA, 'cities', 'cities.shp')
     34        model_def = ogrinspect(shp_file, 'City')
     35
     36        expected = [
     37            '# This is an auto-generated Django model module created by ogrinspect.',
     38            'from django.contrib.gis.db import models',
     39            '',
     40            'class City(models.Model):',
     41            '    name = models.CharField(max_length=80)',
     42            '    population = models.FloatField()',
     43            '    density = models.FloatField()',
     44            '    created = models.DateField()',
     45            '    geom = models.PointField(srid=-1)',
     46            '    objects = models.GeoManager()',
     47        ]
     48
     49        self.assertEqual(model_def, '\n'.join(expected))
     50
     51    @no_spatialite
     52    def test_time_field(self):
     53        # writing shapefules via GDAL currently does not support writing OGRTime
     54        # fields, so we need to actually use a database
     55
     56        model_def = ogrinspect(get_ogr_db_string(None), 'Measurement',
     57                               layer_key=AllOGRFields._meta.db_table,
     58                               decimal=['f_decimal'])
     59
     60        expected = [
     61            '# This is an auto-generated Django model module created by ogrinspect.',
     62            'from django.contrib.gis.db import models',
     63            '',
     64            'class Measurement(models.Model):',
     65            '    f_decimal = models.DecimalField(max_digits=0, decimal_places=0)',
     66            '    f_int = models.IntegerField()',
     67            '    f_datetime = models.DateTimeField()',
     68            '    f_time = models.TimeField()',
     69            '    f_float = models.FloatField()',
     70            '    f_char = models.CharField(max_length=10)',
     71            '    f_date = models.DateField()',
     72            '    geom = models.PolygonField()',
     73            '    objects = models.GeoManager()',
     74        ]
     75
     76        self.assertEqual(model_def, '\n'.join(expected))
     77
     78def get_ogr_db_string(model):
     79    # construct the DB string that GDAL will use to inspect the database.
     80    # GDAL will create its own connection to the database, so we re-use the
     81    # connection settings from the Django test.  This approach is a bit fragile
     82    # and can not work on sqlite test databases (since they are in memory)
     83
     84    db = connections.databases['default']
     85
     86    # map from the django backend into the GDAL database identifier
     87    # http://www.gdal.org/ogr/ogr_formats.html
     88    driver = {
     89        'django.contrib.gis.db.backends.postgis': 'PG',
     90        'django.contrib.gis.db.backends.mysql': 'MYSQL',
     91        'django.contrib.gis.db.backends.oracle': 'OCI',
     92    }[db['ENGINE']]
     93
     94    # build the params of the connection string
     95    params = ["dbname='{0}'".format(db['NAME'])]
     96    def add(key, template):
     97        value = db.get(key, None)
     98        # don't add the parameter if it is not in django's settings
     99        if value is not None:
     100            params.append(template.format(value))
     101    add('HOST', "host='{0}'")
     102    add('PORT', "port='{0}'")
     103    add('USER', "user='{0}'")
     104    add('PASSWORD', "password='{0}'")
     105
     106    return '%s:%s' % (driver, ' '.join(params))
     107
  • django/contrib/gis/utils/ogrinspect.py

    diff --git django/contrib/gis/utils/ogrinspect.py django/contrib/gis/utils/ogrinspect.py
    index fe4443c..aa4e209 100644
    Author: Travis Pinney, Dane Springmeyer, & Justin Bronn 
    88from itertools import izip
    99# Requires GDAL to use.
    1010from django.contrib.gis.gdal import DataSource
    11 from django.contrib.gis.gdal.field import OFTDate, OFTDateTime, OFTInteger, OFTReal, OFTString
     11from django.contrib.gis.gdal.field import OFTDate, OFTDateTime, OFTInteger, OFTReal, OFTString, OFTTime
    1212
    1313def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
    1414    """
    def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non 
    189189            yield '    %s = models.DateField(%s)' % (mfield, kwargs_str[2:])
    190190        elif field_type is OFTDateTime:
    191191            yield '    %s = models.DateTimeField(%s)' % (mfield, kwargs_str[2:])
    192         elif field_type is OFTDate:
     192        elif field_type is OFTTime:
    193193            yield '    %s = models.TimeField(%s)' % (mfield, kwargs_str[2:])
    194194        else:
    195195            raise TypeError('Unknown field type %s in %s' % (field_type, mfield))
Back to Top