Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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
@jdunck jdunck authored
Showing with 72 additions and 20 deletions.
  1. +72 −20 django/contrib/gis/utils/LayerMapping.py
View
92 django/contrib/gis/utils/LayerMapping.py
@@ -20,7 +20,8 @@
model -- GeoDjango model (not an instance)
- source_file -- OGR-supported data source file (e.g. a shapefile)
+ data -- OGR-supported data source file (e.g. a shapefile) or
+ gdal.DataSource instance
mapping -- A python dictionary, keys are strings corresponding
to the GeoDjango model field, and values correspond to
@@ -91,6 +92,9 @@ def __str__(self):
from django.contrib.gis.gdal.Field import Field, OFTInteger, OFTReal, OFTString, OFTDateTime
from django.contrib.gis.models import GeometryColumns, SpatialRefSys
+from django.db import connection, transaction
+from django.core.exceptions import ObjectDoesNotExist
+
# A mapping of given geometry types to their OGR integer type.
ogc_types = {'POINT' : OGRGeomType('Point'),
'LINESTRING' : OGRGeomType('LineString'),
@@ -115,9 +119,22 @@ def __str__(self):
'LINESTRING' : OGRGeomType('MultiLineString'),
'POLYGON' : OGRGeomType('MultiPolygon'),
}
+
+def map_foreign_key(django_field):
+ from django.db.models.fields.related import ForeignKey
+
+ if not django_field.__class__ is ForeignKey:
+ return django_field.__class__.__name__
+
+
+ rf=django_field.rel.get_related_field()
+
+ return rf.get_internal_type()
# The acceptable Django field types that map to OGR fields.
-field_types = {'IntegerField' : OFTInteger,
+field_types = {
+ 'AutoField' : OFTInteger,
+ 'IntegerField' : OFTInteger,
'FloatField' : OFTReal,
'DateTimeField' : OFTDateTime,
'DecimalField' : OFTReal,
@@ -142,10 +159,12 @@ def check_feature(feat, model_fields, mapping):
for model_field, ogr_field in mapping.items():
# Making sure the given mapping model field is in the given model fields.
- if not model_field in model_fields:
- raise Exception, 'Given mapping field "%s" not in given Model fields!' % model_field
- else:
+ if model_field in model_fields:
model_type = model_fields[model_field]
+ elif model_field[:-3] in model_fields: #foreign key
+ model_type = model_fields[model_field[:-3]]
+ else:
+ raise Exception, 'Given mapping field "%s" not in given Model fields!' % model_field
## Handling if we get a geometry in the Field ###
if ogr_field in ogc_types:
@@ -175,7 +194,7 @@ def check_feature(feat, model_fields, mapping):
## Handling other fields
else:
- # Making sure the model field is
+ # Making sure the model field is
if not model_type in field_types:
raise Exception, 'Django field type "%s" has no OGR mapping (yet).' % model_type
@@ -208,14 +227,16 @@ def check_srs(layer, source_srs):
class LayerMapping:
"A class that maps OGR Layers to Django Models."
- def __init__(self, model, ogr_file, mapping, layer=0, source_srs=None):
+ def __init__(self, model, data, mapping, layer=0, source_srs=None):
"Takes the Django model, the mapping (dictionary), and the SHP file."
# Getting the field names and types from the model
- fields = dict((f.name, f.__class__.__name__) for f in model._meta.fields)
-
+ fields = dict((f.name, map_foreign_key(f)) for f in model._meta.fields)
# Getting the DataSource and its Layer
- self.ds = DataSource(ogr_file)
+ if isinstance(data, basestring):
+ self.ds = DataSource(data)
+ else:
+ self.ds = data
self.layer = self.ds[layer]
# 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):
self.mapping = mapping
self.model = model
self.source_srs = check_srs(self.layer, source_srs)
-
+
+ @transaction.commit_on_success
def save(self, verbose=False):
"Runs the layer mapping on the given SHP file, and saves to the database."
@@ -246,14 +268,21 @@ def save(self, verbose=False):
ct = CoordTransform(self.source_srs, target_srs)
except Exception, msg:
raise Exception, 'Could not translate between the data source and model geometry.'
-
+
for feat in self.layer:
# The keyword arguments for model construction
kwargs = {}
# Incrementing through each model field and the OGR field in the mapping
+ all_prepped = True
+
for model_field, ogr_field in self.mapping.items():
- model_type = self.fields[model_field]
+ is_fk = False
+ try:
+ model_type = self.fields[model_field]
+ except KeyError: #foreign key
+ model_type = self.fields[model_field[:-3]]
+ is_fk = True
if ogr_field in ogc_types:
## Getting the OGR geometry from the field
@@ -271,17 +300,40 @@ def save(self, verbose=False):
g.transform(ct)
# Updating the keyword args with the WKT of the transformed model.
- kwargs[model_field] = g.wkt
+ val = g.wkt
else:
## Otherwise, this is an OGR field type
fi = feat.index(ogr_field)
val = feat[fi].value
+
+ if is_fk:
+ rel_obj = None
+ field_name = model_field[:-3]
+ try:
+ #FIXME: refactor to efficiently fetch FKs.
+ # Requires significant re-work. :-/
+ rel = self.model._meta.get_field(field_name).rel
+ rel_obj = rel.to._default_manager.get(**{('%s__exact' % rel.field_name):val})
+ except ObjectDoesNotExist:
+ all_prepped = False
+
+ kwargs[model_field[:-3]] = rel_obj
+ else:
kwargs[model_field] = val
# Constructing the model using the constructed keyword args
- m = self.model(**kwargs)
-
- # Saving the model
- m.save()
- if verbose: print 'Saved: %s' % str(m)
-
+ if all_prepped:
+ m = self.model(**kwargs)
+
+ # Saving the model
+ try:
+ if all_prepped:
+ m.save()
+ if verbose: print 'Saved: %s' % str(m)
+ else:
+ print "Skipping %s due to missing relation." % kwargs
+ except SystemExit:
+ raise
+ except Exception, e:
+ print "Failed to save %s\n Continuing" % kwargs
+
Please sign in to comment.
Something went wrong with that request. Please try again.