LayerMapping data import utility

The LayerMapping class provides a way to map the contents of vector spatial data files (e.g. shapefiles) into GeoDjango models.

This utility grew out of the author’s personal needs to eliminate the code repetition that went into pulling geometries and fields out of a vector layer, converting to another coordinate system (e.g. WGS84), and then inserting into a GeoDjango model.

Note

Use of LayerMapping requires GDAL.

Warning

GIS data sources, like shapefiles, may be very large. If you find that LayerMapping is using too much memory, set DEBUG to False in your settings. When DEBUG is set to True, Django automatically logs every SQL query – and when SQL statements contain geometries, this may consume more memory than is typical.

Example

  1. You need a GDAL-supported data source, like a shapefile (here we’re using a simple polygon shapefile, test_poly.shp, with three features):

    1. >>> from django.contrib.gis.gdal import DataSource
    2. >>> ds = DataSource('test_poly.shp')
    3. >>> layer = ds[0]
    4. >>> print(layer.fields) # Exploring the fields in the layer, we only want the 'str' field.
    5. ['float', 'int', 'str']
    6. >>> print(len(layer)) # getting the number of features in the layer (should be 3)
    7. 3
    8. >>> print(layer.geom_type) # Should be 'Polygon'
    9. Polygon
    10. >>> print(layer.srs) # WGS84 in WKT
    11. GEOGCS["GCS_WGS_1984",
    12. DATUM["WGS_1984",
    13. SPHEROID["WGS_1984",6378137,298.257223563]],
    14. PRIMEM["Greenwich",0],
    15. UNIT["Degree",0.017453292519943295]]
  2. Now we define our corresponding Django model (make sure to use migrate):

    1. from django.contrib.gis.db import models
    2. class TestGeo(models.Model):
    3. name = models.CharField(max_length=25) # corresponds to the 'str' field
    4. poly = models.PolygonField(srid=4269) # we want our model in a different SRID
    5. def __str__(self):
    6. return 'Name: %s' % self.name
  3. Use LayerMapping to extract all the features and place them in the database:

    1. >>> from django.contrib.gis.utils import LayerMapping
    2. >>> from geoapp.models import TestGeo
    3. >>> mapping = {'name' : 'str', # The 'name' model field maps to the 'str' layer field.
    4. 'poly' : 'POLYGON', # For geometry fields use OGC name.
    5. } # The mapping is a dictionary
    6. >>> lm = LayerMapping(TestGeo, 'test_poly.shp', mapping)
    7. >>> lm.save(verbose=True) # Save the layermap, imports the data.
    8. Saved: Name: 1
    9. Saved: Name: 2
    10. Saved: Name: 3

Here, LayerMapping transformed the three geometries from the shapefile in their original spatial reference system (WGS84) to the spatial reference system of the GeoDjango model (NAD83). If no spatial reference system is defined for the layer, use the source_srs keyword with a SpatialReference object to specify one.

LayerMapping API

class LayerMapping(model, data_source, mapping, layer=0, source_srs=None, encoding=None, transaction_mode=’commit_on_success’, transform=True, unique=True, using=’default’)

The following are the arguments and keywords that may be used during instantiation of LayerMapping objects.

ArgumentDescription
modelThe geographic model, not an instance.
data_sourceThe path to the OGR-supported data source file (e.g., a shapefile). Also accepts django.contrib.gis.gdal.DataSource instances.
mappingA dictionary: keys are strings corresponding to the model field, and values correspond to string field names for the OGR feature, or if the model field is a geographic then it should correspond to the OGR geometry type, e.g., ‘POINT’, ‘LINESTRING’, ‘POLYGON’.
Keyword Arguments 
layerThe index of the layer to use from the Data Source (defaults to 0)
source_srsUse this to specify the source SRS manually (for example, some shapefiles don’t come with a ‘.prj’ file). An integer SRID, WKT or PROJ strings, and django.contrib.gis.gdal.SpatialReference objects are accepted.
encodingSpecifies the character set encoding of the strings in the OGR data source. For example, ‘latin-1’, ‘utf-8’, and ‘cp437’ are all valid encoding parameters.
transaction_modeMay be ‘commit_on_success’ (default) or ‘autocommit’.
transformSetting this to False will disable coordinate transformations. In other words, geometries will be inserted into the database unmodified from their original state in the data source.
uniqueSetting this to the name, or a tuple of names, from the given model will create models unique only to the given name(s). Geometries from each feature will be added into the collection associated with the unique model. Forces the transaction mode to be ‘autocommit’.
usingSets the database to use when importing spatial data. Default is ‘default’.

Changed in Django 3.2:

Support for pathlib.Path data_source was added.

save() Keyword Arguments

LayerMapping.``save(verbose=False, fid_range=False, step=False, progress=False, silent=False, stream=sys.stdout, strict=False)

The save() method also accepts keywords. These keywords are used for controlling output logging, error handling, and for importing specific feature ranges.

Save Keyword ArgumentsDescription
fid_rangeMay be set with a slice or tuple of (begin, end) feature ID’s to map from the data source. In other words, this keyword enables the user to selectively import a subset range of features in the geographic data source.
progressWhen this keyword is set, status information will be printed giving the number of features processed and successfully saved. By default, progress information will be printed every 1000 features processed, however, this default may be overridden by setting this keyword with an integer for the desired interval.
silentBy default, non-fatal error notifications are printed to sys.stdout, but this keyword may be set to disable these notifications.
stepIf set with an integer, transactions will occur at every step interval. For example, if step=1000, a commit would occur after the 1,000th feature, the 2,000th feature etc.
streamStatus information will be written to this file handle. Defaults to using sys.stdout, but any object with a write method is supported.
strictExecution of the model mapping will cease upon the first error encountered. The default value (False) behavior is to attempt to continue.
verboseIf set, information will be printed subsequent to each model save executed on the database.

Troubleshooting

Running out of memory

As noted in the warning at the top of this section, Django stores all SQL queries when DEBUG=True. Set DEBUG=False in your settings, and this should stop excessive memory use when running LayerMapping scripts.

MySQL: max_allowed_packet error

If you encounter the following error when using LayerMapping and MySQL:

  1. OperationalError: (1153, "Got a packet bigger than 'max_allowed_packet' bytes")

Then the solution is to increase the value of the max_allowed_packet setting in your MySQL configuration. For example, the default value may be something low like one megabyte – the setting may be modified in MySQL’s configuration file (my.cnf) in the [mysqld] section:

  1. max_allowed_packet = 10M