Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

gis LayerMapping now supports loading while mapping ForeignKey to oth…

…er tables.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@5634 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit d92f68f14bee7ea2f7f772e132734238b26258b3 1 parent f7a23a1
Jeremy Dunck authored July 08, 2007

Showing 1 changed file with 72 additions and 20 deletions. Show diff stats Hide diff stats

  1. 92  django/contrib/gis/utils/LayerMapping.py
92  django/contrib/gis/utils/LayerMapping.py
@@ -20,7 +20,8 @@
20 20
 
21 21
   model -- GeoDjango model (not an instance)
22 22
 
23  
-  source_file -- OGR-supported data source file (e.g. a shapefile)
  23
+  data -- OGR-supported data source file (e.g. a shapefile) or
  24
+          gdal.DataSource instance
24 25
 
25 26
   mapping -- A python dictionary, keys are strings corresponding
26 27
              to the GeoDjango model field, and values correspond to
@@ -91,6 +92,9 @@ def __str__(self):
91 92
 from django.contrib.gis.gdal.Field import Field, OFTInteger, OFTReal, OFTString, OFTDateTime
92 93
 from django.contrib.gis.models import GeometryColumns, SpatialRefSys
93 94
 
  95
+from django.db import connection, transaction
  96
+from django.core.exceptions import ObjectDoesNotExist
  97
+
94 98
 # A mapping of given geometry types to their OGR integer type.
95 99
 ogc_types = {'POINT' : OGRGeomType('Point'),
96 100
              'LINESTRING' : OGRGeomType('LineString'),
@@ -115,9 +119,22 @@ def __str__(self):
115 119
                'LINESTRING' : OGRGeomType('MultiLineString'),
116 120
                'POLYGON' : OGRGeomType('MultiPolygon'),
117 121
                }
  122
+
  123
+def map_foreign_key(django_field):
  124
+    from django.db.models.fields.related import ForeignKey
  125
+
  126
+    if not django_field.__class__ is ForeignKey:
  127
+        return django_field.__class__.__name__
  128
+
  129
+     
  130
+    rf=django_field.rel.get_related_field()
  131
+
  132
+    return rf.get_internal_type()
118 133
                 
119 134
 # The acceptable Django field types that map to OGR fields.
120  
-field_types = {'IntegerField' : OFTInteger,
  135
+field_types = {
  136
+               'AutoField' : OFTInteger,
  137
+               'IntegerField' : OFTInteger,
121 138
                'FloatField' : OFTReal,
122 139
                'DateTimeField' : OFTDateTime,
123 140
                'DecimalField' : OFTReal,
@@ -142,10 +159,12 @@ def check_feature(feat, model_fields, mapping):
142 159
     for model_field, ogr_field in mapping.items():
143 160
 
144 161
         # Making sure the given mapping model field is in the given model fields.
145  
-        if not model_field in model_fields:
146  
-            raise Exception, 'Given mapping field "%s" not in given Model fields!' % model_field
147  
-        else:
  162
+        if model_field in model_fields:
148 163
             model_type = model_fields[model_field]
  164
+        elif model_field[:-3] in model_fields: #foreign key
  165
+            model_type = model_fields[model_field[:-3]]
  166
+        else:
  167
+            raise Exception, 'Given mapping field "%s" not in given Model fields!' % model_field
149 168
 
150 169
         ## Handling if we get a geometry in the Field ###
151 170
         if ogr_field in ogc_types:
@@ -175,7 +194,7 @@ def check_feature(feat, model_fields, mapping):
175 194
 
176 195
         ## Handling other fields 
177 196
         else:
178  
-            # Making sure the model field is 
  197
+            # Making sure the model field is
179 198
             if not model_type in field_types:
180 199
                 raise Exception, 'Django field type "%s" has no OGR mapping (yet).' % model_type
181 200
 
@@ -208,14 +227,16 @@ def check_srs(layer, source_srs):
208 227
 class LayerMapping:
209 228
     "A class that maps OGR Layers to Django Models."
210 229
 
211  
-    def __init__(self, model, ogr_file, mapping, layer=0, source_srs=None):
  230
+    def __init__(self, model, data, mapping, layer=0, source_srs=None):
212 231
         "Takes the Django model, the mapping (dictionary), and the SHP file."
213 232
 
214 233
         # Getting the field names and types from the model
215  
-        fields = dict((f.name, f.__class__.__name__) for f in model._meta.fields)
216  
-
  234
+        fields = dict((f.name, map_foreign_key(f)) for f in model._meta.fields)
217 235
         # Getting the DataSource and its Layer
218  
-        self.ds = DataSource(ogr_file)
  236
+        if isinstance(data, basestring):
  237
+            self.ds = DataSource(data)
  238
+        else:
  239
+            self.ds = data
219 240
         self.layer = self.ds[layer]
220 241
 
221 242
         # Checking the layer -- intitialization of the object will fail if
@@ -227,7 +248,8 @@ def __init__(self, model, ogr_file, mapping, layer=0, source_srs=None):
227 248
         self.mapping = mapping
228 249
         self.model = model
229 250
         self.source_srs = check_srs(self.layer, source_srs)
230  
-        
  251
+
  252
+    @transaction.commit_on_success
231 253
     def save(self, verbose=False):
232 254
         "Runs the layer mapping on the given SHP file, and saves to the database."
233 255
 
@@ -246,14 +268,21 @@ def save(self, verbose=False):
246 268
             ct = CoordTransform(self.source_srs, target_srs)
247 269
         except Exception, msg:
248 270
             raise Exception, 'Could not translate between the data source and model geometry.'
249  
-        
  271
+
250 272
         for feat in self.layer:
251 273
             # The keyword arguments for model construction
252 274
             kwargs = {}
253 275
 
254 276
             # Incrementing through each model field and the OGR field in the mapping
  277
+            all_prepped = True
  278
+
255 279
             for model_field, ogr_field in self.mapping.items():
256  
-                model_type = self.fields[model_field]
  280
+                is_fk = False
  281
+                try:
  282
+                    model_type = self.fields[model_field]
  283
+                except KeyError: #foreign key
  284
+                    model_type = self.fields[model_field[:-3]]
  285
+                    is_fk = True
257 286
 
258 287
                 if ogr_field in ogc_types:
259 288
                     ## Getting the OGR geometry from the field
@@ -271,17 +300,40 @@ def save(self, verbose=False):
271 300
                     g.transform(ct)
272 301
 
273 302
                     # Updating the keyword args with the WKT of the transformed model.
274  
-                    kwargs[model_field] = g.wkt
  303
+                    val = g.wkt
275 304
                 else:
276 305
                     ## Otherwise, this is an OGR field type
277 306
                     fi = feat.index(ogr_field)
278 307
                     val = feat[fi].value
  308
+
  309
+                if is_fk:
  310
+                    rel_obj = None
  311
+                    field_name = model_field[:-3]
  312
+                    try:
  313
+                        #FIXME: refactor to efficiently fetch FKs.
  314
+                        #  Requires significant re-work. :-/
  315
+                        rel = self.model._meta.get_field(field_name).rel
  316
+                        rel_obj = rel.to._default_manager.get(**{('%s__exact' % rel.field_name):val})
  317
+                    except ObjectDoesNotExist:
  318
+                        all_prepped = False
  319
+                    
  320
+                    kwargs[model_field[:-3]] = rel_obj
  321
+                else:
279 322
                     kwargs[model_field] = val
280 323
 
281 324
             # Constructing the model using the constructed keyword args
282  
-            m = self.model(**kwargs)
283  
-
284  
-            # Saving the model
285  
-            m.save()
286  
-            if verbose: print 'Saved: %s' % str(m)
287  
-
  325
+            if all_prepped:
  326
+                m = self.model(**kwargs)
  327
+
  328
+                # Saving the model
  329
+                try:
  330
+                    if all_prepped:
  331
+                        m.save()
  332
+                        if verbose: print 'Saved: %s' % str(m)                        
  333
+                    else:
  334
+                        print "Skipping %s due to missing relation." % kwargs
  335
+                except SystemExit:
  336
+                    raise
  337
+                except Exception, e:
  338
+                    print "Failed to save %s\n  Continuing" % kwargs
  339
+                

0 notes on commit d92f68f

Please sign in to comment.
Something went wrong with that request. Please try again.