8đ
layer_mapping = {
'fk': {'nm_field': 'NAME'}, # foreign key field
'this_field': 'THIS',
'that_field': 'THAT',
'geom': 'POLYGON',
}
the error youâre receiving that the Foreign Key field should be a dictionary is basically requesting an additional mapping to the model which the foreign key relates.
in the above snippet:
- âfkâ is the foreign key field name from the model the data is being loaded into (lets call it âload modelâ)
- ânm_fieldâ is the field name from the model the âload modelâ has the foreign key relationship to (lets call it âprimary modelâ)
- âNAMEâ is the field name from the data being loaded into âload modelâ which holds the relationship to âprimary modelâ
more explicitly, imagine if âprimary modelâ is a dataset of lakes and they have a field called ânm_fieldâ that is the lake name as a string.
now imagine, âload modelâ is a dataset of points representing all the buoys on all the lakes and has a field name âfkâ that is a ForeignKey to âprimary modelâ for the assignment of the lake each buoy belongs to.
finally, the data youâre loading into âload modelâ has a string field called âNAMEâ and it contains the pre-populated name of the lake each buoy belongs to. that string name is the relationship tie. it allows the âload modelâ to use that name to identify which lake in the âprimary modelâ it should establish a foreign key with.
3đ
I tricked the LayerMapper into loading the ForeignKey field as a plain data-type after creating the tables.
- Give USCounty an FK âstateâ to USState and run manage.py syncdb
- Replace the âstateâ with âstate_idâ and the real datatype,
usually models.IntegerField and execute the load.run() LayerMapper. - Return the âstateâ FK to the USCounty model.
-
Use Django normally.
In my case below, the âstateâ keys are 2-character FIPS codes.
class USCounty(models.Model): state = models.ForeignKey(USState) ## state_id = models.CharField(max_length=2) ... geom = models.MultiPolygonField(srid=4326) objects = models.GeoManager()
1đ
I worked around this by manually adding a temporary pre_save callback. You can connect it just for the record creation, then disconnect as soon as LayerMapping has done its work.
See âMy Solutionâ here â the âblack boxâ method I refer to is in fact exactly this use case.
The code that works for me:
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)
- Cannot open manage.py after installing django
- Drf-spectacular is using the wrong AutoSchema to generate Swagger
- Using django message framework with rest_framework
0đ
It doesnât look like there is an easy way to hook into LayerMapping for foreign key fields. I solved this by using a for loop and the get_geoms() call. Thanks to http://invisibleroads.com/tutorials/geodjango-googlemaps-build.html
Here is an example of what I did:
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đ
Not an answer but hopefully a hint.
The error thrown comes from this part of the code. line ~220 of 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.')
At the beginning of the for loop, it looks for a dict: ogr_name.items()
ogr_name is actually defined as the value part of the mapping dict.
The dict is supposed to be composed of the org field name and the related field name from the related model.
If anyone understands the origin of that ogr_name dict, it would be of great use.
- Signal/Method for every executed sql statement
- Password authentication failed for Docker's postgres container
- Django runserver color output
- Django Override Admin change_form.html Template â display associated model in template