我正在尝试使用GeoDjango的LayerMapping功能将我的KML文件导入模型。我正在进行测试,在进行常规导入时没有问题。但是,我最近在我的模型中添加了一个外键。我的模型叫做PlaceMark,它现在有一个名为Layer的模型的FK。我想要
这是我如何从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都引用相关图层。有任何想法吗?
谢谢!拉里
layer_mapping = {
'fk': {'nm_field': 'NAME'}, # foreign key field
'this_field': 'THIS',
'that_field': 'THAT',
'geom': 'POLYGON',
}
您收到的外键字段应该是字典的错误基本上是请求与外键相关的模型的附加映射。
在上面的片段中:
更明确地说,假设“主要模型”是湖泊的数据集,并且它们有一个名为“nm_field”的字段,即湖泊名称作为字符串。
现在想象一下,'加载模型'是表示所有湖泊上所有浮标的点数据集,并且有一个字段名称'fk',它是每个浮标所属湖泊分配的“主要模型”的ForeignKey。
最后,您加载到“加载模型”的数据有一个名为“NAME”的字符串字段,它包含每个浮标所属的湖的预先填充的名称。该字符串名称是关系领带。它允许'加载模型'使用该名称来识别“主要模型”中应该与哪个湖建立外键。
在创建表之后,我欺骗了LayerMapper将ForeignKey字段作为普通数据类型加载。
class USCounty(models.Model):
state = models.ForeignKey(USState)
## state_id = models.CharField(max_length=2)
...
geom = models.MultiPolygonField(srid=4326)
objects = models.GeoManager()
我通过手动添加临时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)
看起来似乎没有一种简单的方法可以挂钩外键字段的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()
不是答案,但希望是一个暗示。
抛出的错误来自代码的这一部分。 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的起源,那将是非常有用的。