TAGS :Viewed: 6 - Published at: a few seconds ago

[ Django: Use LayerMapping to update an existing model? ]

I am working in Django 1.8. I would like to use the LayerMapping import utility to update an existing model.

This is my models file:

class PCT(models.Model):
    code = models.CharField(max_length=3, primary_key=True,
                            help_text='Primary care trust code')
    ons_code = models.CharField(max_length=9, null=True, blank=True)
    name = models.CharField(max_length=200, null=True, blank=True)
    boundary = models.GeometryField(null=True, blank=True)
    objects = models.GeoManager()

I already have a row in the model with code: 03V and name: Corby, and no boundary.

Now I want to import some boundaries for this row from a KML file. This is my import command:

class Command(BaseCommand):
    args = ''
    help = 'Imports boundaries from KML.'

    def handle(self, *args, **options):
        filename = 'CCC_Feb2013.KML' 
        ds = DataSource(filename)
        layer_mapping = {
            'code': 'Name',
            'boundary': 'Unknown'
        }
        lm = LayerMapping(PCT, filename, layer_mapping, transform=False)
        lm.save(strict=True, progress=1, verbose=True)

The problem I'm having is that this seems to wipe the existing row, and create a new one with no name field. Is there any way to update the row using LayerMapping, rather than overwriting it?

Here's a sample of the KML, in case this helps for testing:

<?xml version="1.0" encoding="utf-8"?>
<kml xmlns="http://earth.google.com/kml/2.1">
<Folder>
<description><![CDATA[CCG boundary BSC]]></description>
<Placemark>
<name><![CDATA[03V]]></name>
<description><![CDATA[<br><br><br>
<table border="1" padding="0">
<tr><td>CCGcode</td><td>03V</td></tr>
<tr><td>CCGname</td><td>NHS Corby CCG</td></tr>
    ]]></description>
<visibility>1</visibility>
<open>0</open>
<Style><LineStyle><color>FF000000</color><width>  1</width></LineStyle>   
<PolyStyle><fill>0</fill><outline>1</outline></PolyStyle></Style>
<Polygon>
  <extrude>1</extrude>
  <altitudeMode>clampToGround</altitudeMode> 
  <tessellate>1</tessellate>
  <outerBoundaryIs><LinearRing>
    <coordinates>
          -.596387,52.496896,0
          -.609296,52.508583,0...
    </coordinates>
  </LinearRing></outerBoundaryIs>
  </Polygon> 
  </Placemark>
  ...
  </Folder></kml>

If I can't use LayerMapping, please could you explain how to import the boundary from the KML file, without using LayerMapping?

Answer 1


Try adding unique argument. Looking at the LayerMapping source code that should do an update if model already exists, but I haven't tested it, so let me know if it works:

lm = LayerMapping(PCT, filename, layer_mapping, transform=False, unique='code')

EDIT

But for it to actually update the field it necessary to override LayerMapping.save method. Unfortunately it is not possible to make it very DRY. Extend LayerMapping and copy all the code from original save and replace lines 561 - 565 like so:

from django.contrib.gis.utils.layermapping import LayerMapping

class UpdateLayerMapping(LayerMapping):

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

        ...

                        #geom = getattr(m, self.geom_field).ogr
                        #new = OGRGeometry(kwargs[self.geom_field])
                        #for g in new:
                        #    geom.add(g)
                        #setattr(m, self.geom_field, geom.wkt)
                        for key, value in kwargs.iteritems():
                            setattr(m, key, value)
        ...