Commits

James Rutherford committed 24f577d Draft

Applied patch from issue #13 (field.attname vs. field.name)

Comments (0)

Files changed (1)

shapes/views/export.py

 import datetime
 from django.http import HttpResponse
 from django.utils.encoding import smart_str
+from django.db.models.fields import *
+from django.db.models.fields.related import ForeignKey
 from django.contrib.gis.db.models.fields import GeometryField
 from django.contrib.gis.gdal import check_err, OGRGeomType
 
         self.mimetype = mimetype
         self.file_name = smart_str(file_name)
 
-
     def __call__(self, *args, **kwargs):
         """
         Method that gets called when the ShpResponder class is used as a view.
             self.write_with_native_bindings(*args)
         else:
             self.write_with_ctypes_bindings(*args)
-        
         return tmp.name
 
     def zip_response(self,shapefile_path,file_name,mimetype,readme=None):
         attributes = self.get_attributes()
         
         for field in attributes:
-            field_defn = ogr.FieldDefn(str(field.name),ogr.OFTString)
-            field_defn.SetWidth( 255 )
+            # map django field type to OGR type
+            field_defn = self.map_ogr_types(field)
             if layer.CreateField(field_defn) != 0:
-                raise Exception('Faild to create field')
+                raise Exception('Failed to create field')
         
         feature_def = layer.GetLayerDefn()
         
         for item in queryset:
-            feat = ogr.Feature( feature_def )
+            feat = ogr.Feature(feature_def)
             
             for field in attributes:
-                value = getattr(item,field.name)
-                try:
-                    string_value = str(value)
-                except UnicodeEncodeError, E:
-                    string_value = ''
-                feat.SetField(str(field.name),string_value)
+                # if the field is a foreign key, return its pk value. this is
+                # a problem when a model is given a __unicode__ representation.
+                if isinstance(field,ForeignKey):
+                    value = getattr(getattr(item,field.name),'pk')
+                else:
+                    value = getattr(item,field.name)
+                # truncate the field name.
+                # TODO: handle nonunique truncated field names.
+                feat.SetField(str(field.name[0:10]),value)
               
             geom = getattr(item,geo_field.name)
             
                 # effectively looses whole record in shapefile if geometry does not exist
                 pass
             
-            
             # creat the feature in the layer.
             check_err(lgdal.OGR_L_SetFeature(layer, feat))
         
         # Cleaning up
         check_err(lgdal.OGR_L_SyncToDisk(layer))
         lgdal.OGR_DS_Destroy(ds)
-        lgdal.OGRCleanupAll()
+        lgdal.OGRCleanupAll()
+    
+    def map_ogr_types(self,field,precision=6,width=255):
+        """Map Django field type to OGR field type.
+        FieldDefn = map_ogr_types(Field field, int precision=6, int width=255)
+        
+        Arguments:
+        field -- field in a Django model to map to an OGR data type
+        Keyword Arguments:
+        precision -- float precision.
+        width -- width of string fields.
+        """
+        
+        # Map Django field types to OGR types.
+        ogr_mapping = {AutoField:ogr.OFTInteger,
+                       IntegerField:ogr.OFTInteger,
+                       DateField:ogr.OFTDate,
+                       DateTimeField:ogr.OFTDateTime,
+                       FloatField:ogr.OFTReal,
+                       TextField:ogr.OFTString,
+                       CharField:ogr.OFTString}
+        
+        # Dereference a foreign key if necessary.
+        while isinstance(field,ForeignKey):
+            for f in field.rel.to._meta.fields:
+                if f.attname == field.rel.field_name:
+                    # Don't overwrite the field name! Just interested in the type.
+                    _name = field.name
+                    field = f
+                    field.name = _name
+                    break
+                
+        # Truncate the field name.
+        shpname = field.name[0:10]
+        
+        # Set the OGR field type
+        try:
+            ogr_type = ogr_mapping[type(field)]
+        except KeyError:
+            raise KeyError("OGR type not mapped. Update |ogr_mapping| in |map_ogr_types| method.")
+        
+        # Create the field definition.
+        field_defn = ogr.FieldDefn(str(shpname),ogr_type)
+        
+        # Special operations for OGR field types.
+        if ogr_type == ogr.OFTReal: field_defn.SetPrecision(precision)
+        if ogr_type == ogr.OFTString: field_defn.SetWidth(width)
+        
+        return field_defn