Django

Code

Changeset 5634

Show
Ignore:
Timestamp:
07/08/07 02:07:36 (1 year ago)
Author:
jdunck
Message:

gis LayerMapping? now supports loading while mapping ForeignKey? to other tables.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/gis/django/contrib/gis/utils/LayerMapping.py

    r5613 r5634  
    2121  model -- GeoDjango model (not an instance) 
    2222 
    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 
    2425 
    2526  mapping -- A python dictionary, keys are strings corresponding 
     
    9293from django.contrib.gis.models import GeometryColumns, SpatialRefSys 
    9394 
     95from django.db import connection, transaction 
     96from django.core.exceptions import ObjectDoesNotExist 
     97 
    9498# A mapping of given geometry types to their OGR integer type. 
    9599ogc_types = {'POINT' : OGRGeomType('Point'), 
     
    116120               'POLYGON' : OGRGeomType('MultiPolygon'), 
    117121               } 
     122 
     123def 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() 
    118133                 
    119134# The acceptable Django field types that map to OGR fields. 
    120 field_types = {'IntegerField' : OFTInteger, 
     135field_types = { 
     136               'AutoField' : OFTInteger, 
     137               'IntegerField' : OFTInteger, 
    121138               'FloatField' : OFTReal, 
    122139               'DateTimeField' : OFTDateTime, 
     
    143160 
    144161        # Making sure the given mapping model field is in the given model fields. 
    145         if not model_field in model_fields: 
     162        if model_field in model_fields: 
     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: 
    146167            raise Exception, 'Given mapping field "%s" not in given Model fields!' % model_field 
    147         else: 
    148             model_type = model_fields[model_field] 
    149168 
    150169        ## Handling if we get a geometry in the Field ### 
     
    176195        ## Handling other fields  
    177196        else: 
    178             # Making sure the model field is  
     197            # Making sure the model field is 
    179198            if not model_type in field_types: 
    180199                raise Exception, 'Django field type "%s" has no OGR mapping (yet).' % model_type 
     
    209228    "A class that maps OGR Layers to Django Models." 
    210229 
    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): 
    212231        "Takes the Django model, the mapping (dictionary), and the SHP file." 
    213232 
    214233        # 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) 
    217235        # 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 
    219240        self.layer = self.ds[layer] 
    220241 
     
    228249        self.model = model 
    229250        self.source_srs = check_srs(self.layer, source_srs) 
    230          
     251 
     252    @transaction.commit_on_success 
    231253    def save(self, verbose=False): 
    232254        "Runs the layer mapping on the given SHP file, and saves to the database." 
     
    247269        except Exception, msg: 
    248270            raise Exception, 'Could not translate between the data source and model geometry.' 
    249          
     271 
    250272        for feat in self.layer: 
    251273            # The keyword arguments for model construction 
     
    253275 
    254276            # Incrementing through each model field and the OGR field in the mapping 
     277            all_prepped = True 
     278 
    255279            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 
    257286 
    258287                if ogr_field in ogc_types: 
     
    272301 
    273302                    # Updating the keyword args with the WKT of the transformed model. 
    274                     kwargs[model_field] = g.wkt 
     303                    val = g.wkt 
    275304                else: 
    276305                    ## Otherwise, this is an OGR field type 
    277306                    fi = feat.index(ogr_field) 
    278307                    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: 
    279322                    kwargs[model_field] = val 
    280323 
    281324            # 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