GeoDjango LayerMapping和外键

问题描述 投票:11回答:5

我正在尝试使用GeoDjango的LayerMapping功能将我的KML文件导入模型。我正在进行测试,在进行常规导入时没有问题。但是,我最近在我的模型中添加了一个外键。我的模型叫做PlaceMark,它现在有一个名为Layer的模型的FK。我想要

  1. 覆盖导入并手动设置外键字段的值或
  2. 更新我的KML文件以包含一个新元素,该元素通过Layer的pk或name字段将PlaceMark连接到图层。

这是我如何从shell测试和相关的错误:

>>>from locator import load
>>>load.run()
...
TypeError: ForeignKey mapping must be of dictionary type.
....

这是我的load.py文件:

import os
from django.contrib.gis.utils import LayerMapping
from models import PlaceMark

placemark_mapping = {
    'name' : 'Name',
    'description' : 'Description',
    # This line below is the one that is suspect #
    'layer': 'Layer',
    'geom' : 'POINT25D',
}

placemark_kml = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data/claim.kml'))

def run(verbose=True):
    lm = LayerMapping(PlaceMark, placemark_kml, placemark_mapping,
                      transform=False, encoding='iso-8859-1')

lm.save(strict=True, verbose=verbose)

KML文件:

<?xml version="1.0" encoding="Windows-1252"?>
<kml xmlns="http://earth.google.com/kml/2.1">
<Folder>
  <description><![CDATA[TankSafe_Claims]]></description>
  <Placemark>
    <name><![CDATA[G2184729A]]></name>
    <description><![CDATA[<br><br><br>
    <table border="1" padding="0">
    <tr><td>Policy_Number</td><td>53645645</td></tr>
    <tr><td>Claim_Number</td><td>2342342234</td></tr>
    <tr><td>Policy_Type</td><td>TSP</td></tr>
    <tr><td>Name</td><td>Al's Total</td></tr>
    <tr><td>Street_Address</td><td>555 109th Avenue</td></tr>
    <tr><td>City</td><td>Pullman</td></tr>
    <tr><td>State</td><td>NY</td></tr>
    <tr><td>Zip_Code</td><td>55555</td></tr>
    <tr><td>County</td><td>Allegan</td></tr>
        ]]></description>
    <visibility>1</visibility>
    <open>0</open>
    <Point>
      <extrude>1</extrude>
      <altitudeMode>relativeToGround</altitudeMode>
      <coordinates>-86.092641,42.483953,0</coordinates>
    </Point>
    <!--- ***Should I add the line below?*** -->
    <Layer><name>claims</name></Layer>
  </Placemark>
</Folder>
</kml>

我的目标是让所有导入的PlaceMark都引用相关图层。有任何想法吗?

谢谢!拉里

python django geodjango
5个回答
5
投票
layer_mapping = {
    'fk': {'nm_field': 'NAME'}, # foreign key field
    'this_field': 'THIS',
    'that_field': 'THAT',
    'geom': 'POLYGON',
}

您收到的外键字段应该是字典的错误基本上是请求与外键相关的模型的附加映射。

在上面的片段中:

  • 'fk'是数据加载到的模型中的外键字段名称(让我们称之为'加载模型')
  • 'nm_field'是模型中的字段名称'load model'具有外键关系(让我们称之为'主模型')
  • 'NAME'是加载到'load model'中的数据的字段名称,它与'primary model'保持关系

更明确地说,假设“主要模型”是湖泊的数据集,并且它们有一个名为“nm_field”的字段,即湖泊名称作为字符串。

现在想象一下,'加载模型'是表示所有湖泊上所有浮标的点数据集,并且有一个字段名称'fk',它是每个浮标所属湖泊分配的“主要模型”的ForeignKey。

最后,您加载到“加载模型”的数据有一个名为“NAME”的字符串字段,它包含每个浮标所属的湖的预先填充的名称。该字符串名称是关系领带。它允许'加载模型'使用该名称来识别“主要模型”中应该与哪个湖建立外键。


2
投票

在创建表之后,我欺骗了LayerMapper将ForeignKey字段作为普通数据类型加载。

  • 将USCounty作为FK“州”授予USState并运行manage.py syncdb
  • 将“state”替换为“state_id”和实际数据类型,通常是models.IntegerField并执行load.run()LayerMapper。
  • 将“州”FK返回USCounty模型。
  • 正常使用Django。 在我的情况下,“状态”键是2个字符的FIPS代码。 class USCounty(models.Model): state = models.ForeignKey(USState) ## state_id = models.CharField(max_length=2) ... geom = models.MultiPolygonField(srid=4326) objects = models.GeoManager()

1
投票

我通过手动添加临时pre_save回调来解决这个问题。您可以只为记录创建连接它,然后在LayerMapping完成其工作后立即断开连接。

请参阅“我的解决方案”here - 我所指的“黑匣子”方法实际上就是这个用例。

适用于我的代码:

def pre_save_callback(sender, instance, *args, **kwargs):
    fkey = some_method_that_gets_the_foreign_key()
    instance.type = fkey

# other mappings defined as usual
mapping = {
    'key1': 'KEY1',
    ...,
}

lm = LayerMapping(models.MyModel, PATH_TO_SHAPEFILE, mapping, transform=True)
# temporarily connect pre_save method
pre_save.connect(pre_save_callback, sender=models.MyModel)
try:
    lm.save(strict=True)
except Exception as exc:
    optional_error_handling()
    raise
finally:
    # disconnect pre_save callback
    pre_save.disconnect(pre_save_callback, sender=models.MyModel)

0
投票

看起来似乎没有一种简单的方法可以挂钩外键字段的LayerMapping。我通过使用for循环和get_geoms()调用解决了这个问题。感谢http://invisibleroads.com/tutorials/geodjango-googlemaps-build.html

这是我做的一个例子:

placemark_kml = os.path.abspath(os.path.join(os.path.dirname(locator.__file__), 'data/claim.kml'))
datasource = DataSource(placemark_kml)
lyr = datasource[0]
waypointNames = lyr.get_fields('Name')
waypointDescriptions = lyr.get_fields('Description')
waypointGeometries = lyr.get_geoms()
for waypointName, waypointGeometry, waypointDescription in itertools.izip(waypointNames, waypointGeometries, waypointDescriptions):
    placemark = PlaceMark(name=waypointName, description=waypointDescription, geom=waypointGeometry.wkt)
    placemark.layer = Layer.objects.get(pk=8)
    placemark.save()

0
投票

不是答案,但希望是一个暗示。

抛出的错误来自代码的这一部分。 line~220的layermapping.py

elif isinstance(model_field, models.ForeignKey):
    if isinstance(ogr_name, dict):
        # Is every given related model mapping field in the Layer?
        rel_model = model_field.rel.to
        for rel_name, ogr_field in ogr_name.items():
            idx = check_ogr_fld(ogr_field)
            try:
                rel_model._meta.get_field(rel_name)
            except models.fields.FieldDoesNotExist:
                raise LayerMapError('ForeignKey mapping field "%s" not in %s fields.' %
                                    (rel_name, rel_model.__class__.__name__))
        fields_val = rel_model
    else:
        raise TypeError('ForeignKey mapping must be of dictionary type.')

在for循环的开头,它查找一个dict:ogr_name.items()

ogr_name实际上被定义为映射字典的值部分。 dict应该由组织字段名称和相关模型中的相关字段名称组成。

如果有人理解该ogr_name dict的起源,那将是非常有用的。

© www.soinside.com 2019 - 2024. All rights reserved.