1
2
3
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
13 from osgeo import ogr,osr
14 from django.contrib.gis.gdal import check_err, OGRGeomType
15
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
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
50
51 dr = ogr.GetDriverByName('ESRI Shapefile')
52
53
54
55 tmp = tempfile.NamedTemporaryFile(suffix='.shp', mode='w+b')
56
57 tmp.close()
58
59
60
61 ds = dr.CreateDataSource(tmp.name)
62 if ds is None:
63 raise Exception('Could not create file!')
64
65
66 if hasattr(geo_field,'geom_type'):
67
68 ogr_type = OGRGeomType(geo_field.geom_type).num
69 else:
70
71 ogr_type = OGRGeomType(geo_field._geom).num
72
73
74 native_srs = osr.SpatialReference()
75 if hasattr(geo_field,'srid'):
76
77 native_srs.ImportFromEPSG(geo_field.srid)
78 else:
79
80 native_srs.ImportFromEPSG(geo_field._srid)
81
82
83
84
85
86
87
88 output_srs = native_srs
89
90
91
92
93
94 layer = ds.CreateLayer('lyr',srs=output_srs,geom_type=ogr_type)
95
96
97
98 for field in attributes:
99
100
101
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
114
115 feature_def = layer.GetLayerDefn()
116
117
118 for item in self.queryset:
119
120 feat = ogr.Feature(feature_def)
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
153 value = ''
154
155
156
157
158
159
160 feat.SetField(idx, value)
161 idx += 1
162
163
164 geom = getattr(item,geo_field.name)
165
166
167
168 if geom:
169
170 ogr_geom = ogr.CreateGeometryFromWkt(geom.wkt)
171
172
173
174
175 check_err(feat.SetGeometry(ogr_geom))
176 else:
177
178
179 pass
180
181
182
183 check_err(layer.CreateFeature(feat))
184
185
186
187
188
189 ds.Destroy()
190
191 if 'return_file_not_response' in args:
192 return tmp.name
193 else:
194
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
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