LayerMapping 是一个数据导入实用程序

LayerMapping 类提供了一种将矢量空间数据文件(例如 shapefile)的内容映射到 GeoDjango 模型的方法。

这个实用程序是为了消除重复的代码,用于从矢量图层中提取几何和字段,将其转换为另一个坐标系统(例如 WGS84),然后插入到 GeoDjango 模型中而产生的。

备注

使用 LayerMapping 需要 GDAL。

警告

GIS 数据源,如 shapefile,可能非常大。如果发现 LayerMapping 使用了过多的内存,请在您的设置中将 DEBUG 设置为 False。当 DEBUG 设置为 True 时,Django 会自动记录 每个 SQL 查询 — 当 SQL 语句包含几何信息时,这可能会消耗比通常更多的内存。

例如

  1. 您需要一个受 GDAL 支持的数据源,比如一个 shapefile(这里我们使用一个简单的多边形 shapefile,名为 test_poly.shp,包含三个要素):
  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]]
  1. 现在我们定义相应的 Django 模型(确保使用 migrate):

    ``` from django.contrib.gis.db import models

  1. class TestGeo(models.Model):
  2. name = models.CharField(max_length=25) # corresponds to the 'str' field
  3. poly = models.PolygonField(srid=4269) # we want our model in a different SRID
  4. def __str__(self):
  5. return "Name: %s" % self.name
  6. ```
  1. 使用 LayerMapping 提取所有要素并将它们放入数据库中:
  1. >>> from django.contrib.gis.utils import LayerMapping
  2. >>> from geoapp.models import TestGeo
  3. >>> mapping = {
  4. ... "name": "str", # The 'name' model field maps to the 'str' layer field.
  5. ... "poly": "POLYGON", # For geometry fields use OGC name.
  6. ... } # The mapping is a dictionary
  7. >>> lm = LayerMapping(TestGeo, "test_poly.shp", mapping)
  8. >>> lm.save(verbose=True) # Save the layermap, imports the data.
  9. Saved: Name: 1
  10. Saved: Name: 2
  11. Saved: Name: 3

在这里,LayerMapping 将来自 shapefile 的三个几何图形从其原始空间参考系统(WGS84)转换为 GeoDjango 模型的空间参考系统(NAD83)。如果未为图层定义空间参考系统,请使用 source_srs 关键字并提供一个 SpatialReference 对象来指定一个。

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’)

以下是在实例化 LayerMapping 对象期间可以使用的参数和关键字:

参数描述
model地理模型,不是 实例
data_sourceOGR 支持的数据源文件的路径(例如,shapefile)。也接受 django.contrib.gis.gdal.DataSource 实例。
mapping一个字典:键是与模型字段对应的字符串,值对应于 OGR 要素的字符串字段名称,或者如果模型字段是地理字段,则应该对应于 OGR 几何类型,例如 ‘POINT’‘LINESTRING’‘POLYGON’
关键字参数 
layer要使用的数据源中的图层的索引(默认为0)。
source_srs使用这个参数可以手动指定源空间参考系统(例如,一些 shapefile 文件不包含 ‘.prj’ 文件)。可以接受整数 SRID、WKT 或 PROJ 字符串以及 django.contrib.gis.gdal.SpatialReference 对象。
encoding指定 OGR 数据源中字符串的字符集编码。例如,‘latin-1’‘utf-8’‘cp437’ 都是有效的编码参数。
transaction_mode可以是 ‘commit_on_success’ (默认)或 ‘autocommit’
transform将其设置为 False 将禁用坐标转换。换句话说,几何图形将以其在数据源中的原始状态未经修改地插入到数据库中。
unique将其设置为给定模型的名称或名称元组将创建仅与给定名称唯一的模型。每个要素的几何图形将添加到与唯一模型关联的集合中。强制事务模式为 ‘autocommit’
using在导入空间数据时设置要使用的数据库。默认为 ‘default’

save() 关键字参数

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

save() 方法还接受关键字。这些关键字用于控制输出日志、错误处理和导入特定要素范围。

保存关键字参数描述
fid_range可以设置为要从数据源中映射的(begin, end)要素 ID 的切片或元组。换句话说,这个关键字允许用户有选择地导入地理数据源中的子集范围内的要素。
progress当设置了这个关键字时,将打印状态信息,显示已处理和成功保存的要素数量。默认情况下,将在处理每 1000 个要素时打印进度信息,但可以通过将这个关键字设置为所需间隔的整数来覆盖默认值。
silent默认情况下,非致命错误通知将打印到 sys.stdout,但可以通过设置这个关键字来禁用这些通知。
step如果设置为整数,事务将在每个步骤间隔之后发生。例如,如果 step=1000,则在第 1000 个要素、第 2000 个要素等之后会发生提交。
stream状态信息将被写入到这个文件句柄。默认使用 sys.stdout,但支持任何具有 write 方法的对象。
strict在遇到第一个错误时,模型映射的执行将停止。默认值(False)的行为是尝试继续进行。
verbose如果设置,将在执行数据库上的每个模型保存后打印信息。

错误调试

内存耗尽

如本节顶部的警告所述,当 DEBUG=True 时,Django 会存储所有的 SQL 查询。在您的设置中设置 DEBUG=False,这应该可以阻止运行 LayerMapping 脚本时过多的内存使用。

MySQL: max_allowed_packet 错误

如果在使用 LayerMapping 和 MySQL 时遇到以下错误:

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

解决方法是增加 MySQL 配置中的 max_allowed_packet 设置的值。例如,默认值可能很低,比如一兆字节 —— 可以在 MySQL 的配置文件(my.cnf)中的 [mysqld] 部分修改该设置:

  1. max_allowed_packet = 10M