Package madrona :: Package shapes :: Package views :: Module export
[hide private]

Source Code for Module madrona.shapes.views.export

  1  # -*- coding: utf-8 -*- 
  2  ### I'm porting this over to use osgeo ogr instead of the libgdal version 'cause I can't get that to work 
  3  ### I'm going to use ### to comment out the lines that I'm changing.  The replacement will be below. 
  4  import os 
  5  import zipfile 
  6  import tempfile 
  7  import datetime 
  8  import cStringIO 
  9  from django.http import HttpResponse 
 10  from django.utils.encoding import smart_str 
 11  from django.contrib.gis.db.models.fields import GeometryField 
 12  ###from django.contrib.gis.gdal.libgdal import lgdal as ogr 
 13  from osgeo import ogr,osr 
 14  from django.contrib.gis.gdal import check_err, OGRGeomType # Driver, OGRGeometry, OGRGeomType, SpatialReference, check_err, CoordTransform 
 15   
16 -class ShpResponder(object):
17 - def __init__(self, queryset, readme=None, geo_field=None, proj_transform=None, mimetype='application/zip',file_name='shp_download'):
18 """ 19 """ 20 self.queryset = queryset 21 self.readme = readme 22 self.geo_field = geo_field 23 self.proj_transform = proj_transform 24 self.mimetype = mimetype 25 self.file_name = smart_str(file_name)
26
27 - def __call__(self, *args, **kwargs):
28 """ 29 """ 30 fields = self.queryset.model._meta.fields 31 geo_fields = [f for f in fields if isinstance(f, GeometryField)] 32 geo_fields_names = ', '.join([f.name for f in geo_fields]) 33 attributes = [f for f in fields if not isinstance(f, GeometryField)] 34 35 if len(geo_fields) > 1: 36 if not self.geo_field: 37 raise ValueError("More than one geodjango geometry field found, please specify which to use by name using the 'geo_field' keyword. Available fields are: '%s'" % geo_fields_names) 38 else: 39 geo_field_by_name = [fld for fld in geo_fields if fld.name == self.geo_field] 40 if not geo_field_by_name: 41 raise ValueError("Geodjango geometry field not found with the name '%s', fields available are: '%s'" % (self.geo_field,geo_fields_names)) 42 else: 43 geo_field = geo_field_by_name[0] 44 elif geo_fields: 45 geo_field = geo_fields[0] 46 else: 47 raise ValueError('No geodjango geometry fields found in this model queryset') 48 49 # Get the shapefile driver 50 ###dr = Driver('ESRI Shapefile') 51 dr = ogr.GetDriverByName('ESRI Shapefile') 52 53 # create a temporary file to write the shapefile to 54 # since we are ultimately going to zip it up 55 tmp = tempfile.NamedTemporaryFile(suffix='.shp', mode='w+b') 56 # we must close the file for GDAL to be able to open and write to it 57 tmp.close() 58 59 # Creating the datasource 60 ###ds = ogr.OGR_Dr_CreateDataSource(dr._ptr, tmp.name, None) 61 ds = dr.CreateDataSource(tmp.name) 62 if ds is None: 63 raise Exception('Could not create file!') 64 65 # Get the right geometry type number for ogr 66 if hasattr(geo_field,'geom_type'): 67 ###ogr_type = OGRGeomType(geo_field.geom_type).num 68 ogr_type = OGRGeomType(geo_field.geom_type).num 69 else: 70 ###ogr_type = OGRGeomType(geo_field._geom).num 71 ogr_type = OGRGeomType(geo_field._geom).num 72 73 # Set up the native spatial reference of the geometry field using the srid 74 native_srs = osr.SpatialReference() 75 if hasattr(geo_field,'srid'): 76 ###native_srs = SpatialReference(geo_field.srid) 77 native_srs.ImportFromEPSG(geo_field.srid) 78 else: 79 ###native_srs = SpatialReference(geo_field._srid) 80 native_srs.ImportFromEPSG(geo_field._srid) 81 82 ###if self.proj_transform: 83 ### output_srs = SpatialReference(self.proj_transform) 84 ### ct = CoordTransform(native_srs, output_srs) 85 ###else: 86 ### output_srs = native_srs 87 88 output_srs = native_srs 89 90 # create the layer 91 # print 'about to try to create data layer' 92 # print 'ds: %s, path: %s' % (ds, tmp.name) 93 ###layer = ogr.OGR_DS_CreateLayer(ds, tmp.name, output_srs._ptr, ogr_type, None) 94 layer = ds.CreateLayer('lyr',srs=output_srs,geom_type=ogr_type) 95 96 # Create the fields 97 # Todo: control field order as param 98 for field in attributes: 99 ###fld = ogr.OGR_Fld_Create(str(field.name), 4) 100 ###added = ogr.OGR_L_CreateField(layer, fld, 0) 101 ###check_err(added) 102 103 if field.__class__.__name__ == 'FloatField': 104 field_defn = ogr.FieldDefn(str(field.name),ogr.OFTReal) 105 elif field.__class__.__name__ == 'IntegerField': 106 field_defn = ogr.FieldDefn(str(field.name),ogr.OFTInteger) 107 else: 108 field_defn = ogr.FieldDefn(str(field.name),ogr.OFTString) 109 field_defn.SetWidth(255) 110 if layer.CreateField(field_defn) != 0: 111 raise Exception('Faild to create field') 112 113 # Getting the Layer feature definition. 114 ###feature_def = ogr.OGR_L_GetLayerDefn(layer) 115 feature_def = layer.GetLayerDefn() 116 117 # Loop through queryset creating features 118 for item in self.queryset: 119 ###feat = ogr.OGR_F_Create(feature_def) 120 feat = ogr.Feature(feature_def) 121 122 # For now, set all fields as strings 123 # TODO: catch model types and convert to ogr fields 124 # http://www.gdal.org/ogr/classOGRFeature.html 125 126 # OGR_F_SetFieldDouble 127 #OFTReal => FloatField DecimalField 128 129 # OGR_F_SetFieldInteger 130 #OFTInteger => IntegerField 131 132 #OGR_F_SetFieldStrin 133 #OFTString => CharField 134 135 # OGR_F_SetFieldDateTime() 136 #OFTDateTime => DateTimeField 137 #OFTDate => TimeField 138 #OFTDate => DateField 139 140 idx = 0 141 for field in attributes: 142 value = getattr(item,field.name) 143 144 if field.__class__.__name__ == 'FloatField': 145 value = float(value) 146 elif field.__class__.__name__ == 'IntegerField': 147 value = int(value) 148 else: 149 try: 150 value = str(value) 151 except UnicodeEncodeError, E: 152 # http://trac.osgeo.org/gdal/ticket/882 153 value = '' 154 155 ###ogr.OGR_F_SetFieldString(feat, idx, string_value) 156 #changing the following SetField command from accessing field by name to index 157 #this change solves an issue that arose sometime after gdal 1.6.3 158 #in which the field names became truncated to 10 chars in CreateField 159 #feat.SetField(str(field.name),string_value) 160 feat.SetField(idx, value) 161 idx += 1 162 163 # Transforming & setting the geometry 164 geom = getattr(item,geo_field.name) 165 166 # if requested we transform the input geometry 167 # to match the shapefiles projection 'to-be' 168 if geom: 169 ###ogr_geom = OGRGeometry(geom.wkt,output_srs) 170 ogr_geom = ogr.CreateGeometryFromWkt(geom.wkt) 171 ###if self.proj_transform: 172 ### ogr_geom.transform(ct) 173 # create the geometry 174 ###check_err(ogr.OGR_F_SetGeometry(feat, ogr_geom._ptr)) 175 check_err(feat.SetGeometry(ogr_geom)) 176 else: 177 # Case where geometry object is not found because of null value for field 178 # effectively looses whole record in shapefile if geometry does not exist 179 pass 180 181 # creat the feature in the layer. 182 ###check_err(ogr.OGR_L_SetFeature(layer, feat)) 183 check_err(layer.CreateFeature(feat)) 184 185 # Cleaning up 186 ###check_err(ogr.OGR_L_SyncToDisk(layer)) 187 ###ogr.OGR_DS_Destroy(ds) 188 ###ogr.OGRCleanupAll() 189 ds.Destroy() 190 191 if 'return_file_not_response' in args: 192 return tmp.name 193 else: 194 # Read resulting shapefile into a zipfile buffer 195 buffer = cStringIO.StringIO() 196 zip = zipfile.ZipFile(buffer, 'w', zipfile.ZIP_DEFLATED) 197 files = ['shp','shx','prj','dbf'] 198 for item in files: 199 filename = '%s.%s' % (tmp.name.replace('.shp',''), item) 200 zip.write(filename, arcname='%s.%s' % (self.file_name.replace('.shp',''), item)) 201 if self.readme: 202 zip.writestr('README.txt',self.readme) 203 zip.close() 204 buffer.flush() 205 zip_stream = buffer.getvalue() 206 buffer.close() 207 # Stick it all in a django HttpResponse 208 response = HttpResponse() 209 response['Content-Disposition'] = 'attachment; filename=%s.zip' % self.file_name.replace('.shp','') 210 response['Content-length'] = str(len(zip_stream)) 211 response['Content-Type'] = self.mimetype 212 response.write(zip_stream) 213 return response
214