【问题标题】:GeoDjango LayerMapping & Foreign KeyGeoDjango 图层映射和外键
【发布时间】:2014-01-17 22:54:24
【问题描述】:

我正在尝试使用 GeoDjango 的 LayerMapping 功能将我的 KML 文件导入模型。我已经运行测试并且在进行常规导入时没有问题。但是,我最近在我的模型中添加了一个外键。我的模型称为 PlaceMark,它现在有一个名为 Layer 的模型的 FK。我也愿意

  1. 覆盖导入并手动设置外键字段的值或
  2. 更新我的 KML 文件以包含一个新元素,该元素通过图层的 pk 或名称字段将 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


    【解决方案1】:
    layer_mapping = {
        'fk': {'nm_field': 'NAME'}, # foreign key field
        'this_field': 'THIS',
        'that_field': 'THAT',
        'geom': 'POLYGON',
    }
    

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

    在上面的sn-p中:

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

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

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

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

    【讨论】:

      【解决方案2】:

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

      • 给 USCounty 一个 FK“状态”给 USState 并运行 manage.py syncdb
      • 用“state_id”和真实数据类型替换“state”, 通常是 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()
        

      【讨论】:

      • 我也在做同样的事情,但我对这个 hack 真的很不满意。我希望能够从我的 .shp 文件中创建和加载数据库,而无需手动干预
      【解决方案3】:

      我通过手动添加一个临时的 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)
      

      【讨论】:

        【解决方案4】:

        看起来没有一种简单的方法可以将外键字段挂接到 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()
        

        【讨论】:

          【解决方案5】:

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

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

          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 应该由 org 字段名称和相关模型中的相关字段名称组成。

          如果有人了解那个 ogr_name 字典的来源,那将很有用。

          【讨论】:

            猜你喜欢
            • 2019-09-13
            • 2021-07-01
            • 2011-08-08
            • 1970-01-01
            • 2012-11-23
            • 1970-01-01
            • 1970-01-01
            • 2015-02-12
            相关资源
            最近更新 更多