def get_tile(self, x, y, z, extent=4096, buffer=256, clip_geom=True): # get tile coordinates from x, y and z xmin, ymin, xmax, ymax = self.get_bounds(x, y, z) features = self.get_vector_tile_queryset() # keep features intersecting tile filters = { f"{self.vector_tile_geom_name}__intersects": Transform(MakeEnvelope(xmin, ymin, xmax, ymax, 3857), 4326) } features = features.filter(**filters) # annotate prepared geometry for MVT features = features.annotate(geom_prepared=AsMVTGeom( Transform(self.vector_tile_geom_name, 3857), MakeEnvelope(xmin, ymin, xmax, ymax, 3857), extent, buffer, clip_geom)) fields = self.vector_tile_fields + ( "geom_prepared", ) if self.vector_tile_fields else ( "geom_prepared", ) # keep values to include in tile (extra included_fields + geometry) features = features.values(*fields) # generate MVT with connection.cursor() as cursor: cursor.execute( "SELECT ST_ASMVT(subquery.*, %s, %s, %s) FROM ({}) as subquery" .format(features.query), params=[ self.get_vector_tile_layer_name(), extent, "geom_prepared" ]) row = cursor.fetchone()[0] return row.tobytes() if row else None
def test_distance_transform(self): """ Test the `Distance` function used with `Transform` on a geographic field. """ # We'll be using a Polygon (created by buffering the centroid # of 77005 to 100m) -- which aren't allowed in geographic distance # queries normally, however our field has been transformed to # a non-geographic system. z = SouthTexasZipcode.objects.get(name='77005') # Reference query: # SELECT ST_Distance(ST_Transform("distapp_censuszipcode"."poly", 32140), # ST_GeomFromText('<buffer_wkt>', 32140)) # FROM "distapp_censuszipcode"; dists_m = [3553.30384972258, 1243.18391525602, 2186.15439472242] # Having our buffer in the SRID of the transformation and of the field # -- should get the same results. The first buffer has no need for # transformation SQL because it is the same SRID as what was given # to `transform()`. The second buffer will need to be transformed, # however. buf1 = z.poly.centroid.buffer(100) buf2 = buf1.transform(4269, clone=True) ref_zips = ['77002', '77025', '77401'] for buf in [buf1, buf2]: qs = CensusZipcode.objects.exclude( name='77005').annotate(distance=Distance( Transform('poly', 32140), buf)).order_by('name') self.assertEqual(ref_zips, sorted([c.name for c in qs])) for i, z in enumerate(qs): self.assertAlmostEqual(z.distance.m, dists_m[i], 5)
def get_tile(self, x, y, z, extent=4096, buffer=256, clip_geom=True): # get tile coordinates from x, y and z west, south, east, north = self.get_bounds(x, y, z) features = self.get_vector_tile_queryset() pixel = self.pixel_length(z) final_buffer = 4 * pixel bbox = Polygon.from_bbox((west - final_buffer, south - final_buffer, east + final_buffer, north + final_buffer)) bbox.srid = 3857 filters = { f"{self.vector_tile_geom_name}__intersects": bbox } features = features.filter(**filters) features = features.annotate(clipped=Intersection(Transform(self.vector_tile_geom_name, 3857), bbox)) if features: tile = { "name": self.get_vector_tile_layer_name(), "features": [ { "geometry": feature.clipped.simplify(pixel, preserve_topology=True).wkb.tobytes(), "properties": { key: getattr(feature, key) for key in self.vector_tile_fields if self.vector_tile_fields } } for feature in features ], } return mapbox_vector_tile.encode(tile, quantize_bounds=(west, south, east, north), extents=extent)
def get_queryset(self): qs = Site.objects.filter(published=True) if 'source' in self.request.GET: qs = qs.filter(source__name__in=self.request.GET['source'].split(',')) if 'portal' in self.request.GET: qs = qs.filter(Q(portal__name=self.request.GET['portal']) | Q(portal=None)) return qs.annotate(api_geom=Transform("geom", settings.API_SRID))
def get_queryset(self): pk = self.kwargs['pk'] dive = get_object_or_404(Dive.objects.existing(), pk=pk) if not dive.is_public(): raise Http404 return dive.services.filter(type__published=True).annotate( api_geom=Transform("geom", settings.API_SRID))
def get_queryset(self): pk = self.kwargs['pk'] trek = get_object_or_404(Trek.objects.existing(), pk=pk) if not self.request.user.has_perm( 'trekking.read_service') and not trek.is_public(): raise Http404 return trek.services.filter(type__published=True).annotate( api_geom=Transform("geom", settings.API_SRID))
def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB_ALIAS): """ This view generates KML for the given app label, model, and field name. The model's default manager must be GeoManager, and the field name must be that of a geographic field. """ placemarks = [] try: klass = apps.get_model(label, model) except LookupError: raise Http404( 'You must supply a valid app label and module name. Got "%s.%s"' % (label, model)) if field_name: try: field = klass._meta.get_field(field_name) if not isinstance(field, GeometryField): raise FieldDoesNotExist except FieldDoesNotExist: raise Http404('Invalid geometry field.') connection = connections[using] if connection.features.has_AsKML_function: # Database will take care of transformation. placemarks = klass._default_manager.using(using).annotate( kml=AsKML(field_name)) else: # If the database offers no KML method, we use the `kml` # attribute of the lazy geometry instead. placemarks = [] if connection.features.has_Transform_function: qs = klass._default_manager.using(using).annotate( **{'%s_4326' % field_name: Transform(field_name, 4326)}) field_name += '_4326' else: qs = klass._default_manager.using(using).all() for mod in qs: mod.kml = getattr(mod, field_name).kml placemarks.append(mod) # Getting the render function and rendering to the correct. if compress: render = render_to_kmz else: render = render_to_kml return render('gis/kml/placemarks.kml', {'places': placemarks})
def test_perimeter_geodetic(self): # Currently only Oracle supports calculating the perimeter on geodetic # geometries (without being transformed). qs1 = CensusZipcode.objects.annotate(perim=Perimeter('poly')) if connection.features.supports_perimeter_geodetic: self.assertAlmostEqual(qs1[0].perim.m, 18406.3818954314, 3) else: with self.assertRaises(NotSupportedError): list(qs1) # But should work fine when transformed to projected coordinates qs2 = CensusZipcode.objects.annotate(perim=Perimeter(Transform('poly', 32140))).filter(name='77002') self.assertAlmostEqual(qs2[0].perim.m, 18404.355, 3)
def get_queryset(self): qs = _aquifer_qs(self.request) qs = qs.annotate( extent=Cast(Transform(Func('geom', function='ST_Envelope'), 4326), output_field=TextField())) return qs.values('aquifer_id', 'aquifer_name', 'location_description', 'demand__description', 'material__description', 'subtype__description', 'vulnerability__description', 'productivity__description', 'area', 'mapping_year', 'litho_stratographic_unit', 'retire_date', 'extent')
def get_queryset(self): dive = get_object_or_404(Dive.objects.existing(), pk=self.kwargs['pk']) queryset = dive.touristic_events.filter(published=True) if 'source' in self.request.GET: queryset = queryset.filter( source__name__in=self.request.GET['source'].split(',')) if 'portal' in self.request.GET: queryset = queryset.filter( portal__name=self.request.GET['portal']) return queryset.annotate( api_geom=Transform("geom", settings.API_SRID))
def serialize(self, treks): self.xml.startDocument() self.xml.startElement('circuits', {'version': '2'}) for trek in treks: self.xml.startElement( 'circuit', { 'date_creation': timestamp(trek.date_insert), 'date_modification': timestamp(trek.date_update), 'id_circuit': str(trek.pk), }) orig_lang = translation.get_language() self.xml.startElement('informations', {}) for lang in trek.published_langs: translation.activate(lang) self.xml.startElement('information', {'langue': lang}) self.serialize_field('titre', trek.name) self.serialize_description(trek) self.serialize_medias(self.request, trek.serializable_pictures) if any([getattr(trek, name) for name in self.ADDITIONNAL_INFO]): self.xml.startElement('informations_complementaires', {}) for name in self.ADDITIONNAL_INFO: self.serialize_additionnal_info(trek, name) self.xml.endElement('informations_complementaires') self.serialize_tags(trek) self.xml.endElement('information') translation.activate(orig_lang) self.xml.endElement('informations') self.serialize_field('distance', int(trek.length)) self.serialize_locomotions(trek) kml_url = reverse('trekking:trek_kml_detail', kwargs={ 'lang': get_language(), 'pk': trek.pk, 'slug': trek.slug }) self.serialize_field( 'fichier_trace', '', {'url': self.request.build_absolute_uri(kml_url)}) if not self.exclude_pois: if trek.published_pois: self.xml.startElement('pois', {}) self.serialize_pois( trek.published_pois.annotate( transformed_geom=Transform('geom', 4326))) self.xml.endElement('pois') self.xml.endElement('circuit') self.xml.endElement('circuits') self.xml.endDocument()
def get_queryset(self): qs = self.model.objects.existing() qs = qs.select_related('structure', 'difficulty', 'practice') qs = qs.prefetch_related('levels', 'source', 'portal', 'themes', 'attachments') qs = qs.filter(published=True).order_by('pk').distinct('pk') if 'source' in self.request.GET: qs = qs.filter( source__name__in=self.request.GET['source'].split(',')) if 'portal' in self.request.GET: qs = qs.filter( Q(portal__name=self.request.GET['portal']) | Q(portal=None)) qs = qs.annotate(api_geom=Transform("geom", settings.API_SRID)) return qs
def filter_queryset(self, request, queryset, view): point = request.query_params.get('point', None) radius = request.query_params.get('radius', None) srid = request.query_params.get('srid', 4326) if point and radius: try: shape = GEOSGeometry(point, srid=int(srid)) assert shape.geom_type == 'Point' except (ValueError, AssertionError, GDALException, GEOSException): pass else: shape.transform(3005) queryset = queryset.annotate(geom_albers=Transform('geom', 3005)) \ .filter(geom_albers__dwithin=(shape, D(m=radius))) return queryset
def get_queryset(self): trek = get_object_or_404(Trek.objects.existing(), pk=self.kwargs['pk']) if not trek.is_public(): raise Http404 queryset = trek.touristic_contents.filter(published=True) if 'categories' in self.request.GET: queryset = queryset.filter( category__pk__in=self.request.GET['categories'].split(',')) if 'source' in self.request.GET: queryset = queryset.filter( source__name__in=self.request.GET['source'].split(',')) if 'portal' in self.request.GET: queryset = queryset.filter(portal__name=self.request.GET['portal']) return queryset.annotate(api_geom=Transform("geom", settings.API_SRID))
def get_queryset(self): qs = self.model.objects.existing() qs = qs.select_related('structure', 'difficulty', 'practice', 'route') qs = qs.prefetch_related( 'networks', 'source', 'portal', 'web_links', 'accessibilities', 'themes', 'aggregations', 'information_desks', 'attachments', Prefetch('trek_relationship_a', queryset=TrekRelationship.objects.select_related( 'trek_a', 'trek_b')), Prefetch('trek_relationship_b', queryset=TrekRelationship.objects.select_related( 'trek_a', 'trek_b')), Prefetch('trek_children', queryset=OrderedTrekChild.objects.select_related( 'parent', 'child')), Prefetch('trek_parents', queryset=OrderedTrekChild.objects.select_related( 'parent', 'child')), ) qs = qs.filter(Q(published=True) | Q(trek_parents__parent__published=True)).distinct('practice__order', 'pk').\ order_by('-practice__order', 'pk') if 'source' in self.request.GET: qs = qs.filter( source__name__in=self.request.GET['source'].split(',')) if 'portal' in self.request.GET: qs = qs.filter( Q(portal__name=self.request.GET['portal']) | Q(portal=None)) qs = qs.annotate(api_geom=Transform("geom", settings.API_SRID)) return qs
def guess_maxzoom(layer): features = layer.features.all() layer_query = features.annotate(geom3857=Transform('geom', EPSG_3857)) layer_raw_query, args = layer_query.query.sql_with_params() try: with connection.cursor() as cursor: sql_query = f''' WITH q1 AS ({layer_raw_query}), q2 AS (SELECT ST_X((ST_DumpPoints(geom3857)).geom) AS x FROM q1), q3 AS (SELECT x - lag(x) OVER (ORDER BY x) AS dst FROM q2), q4 AS (SELECT * FROM q3 WHERE dst > 0) SELECT exp(sum(ln(dst))/count(dst)) AS avg FROM q4 ''' cursor.execute(sql_query, args) row = cursor.fetchone() # geometric mean of the |x_{i+1}-x_i| for all points (x,y) in layer.pk avg = row[0] # total number of pixels to represent length `avg` (equator) nb_pixels_total = 2 * pi * EARTH_RADIUS / avg tile_resolution = VectorTile.TILE_WIDTH_PIXEL * VectorTile.EXTENT_RATIO # zoom (ceil) to fit those pixels at `tile_resolution` max_zoom = ceil(log(nb_pixels_total / tile_resolution, 2)) return min(max_zoom, 22) except TypeError: return 14 # Arbitrary zoom value
def get_tile(self, x, y, z, name=None, features_pks=None): xmin, ymin, xmax, ymax = self.get_tile_bbox(x, y, z) pixel_width_x, pixel_width_y = self.pixel_widths( xmin, ymin, xmax, ymax) # Intersects on internal data projection using pixel buffer layer_query = self.layer.features.filter( geom__intersects=Transform( MakeEnvelope(xmin - pixel_width_x * self.pixel_buffer, ymin - pixel_width_y * self.pixel_buffer, xmax + pixel_width_x * self.pixel_buffer, ymax + pixel_width_y * self.pixel_buffer, EPSG_3857), app_settings.INTERNAL_GEOMETRY_SRID))\ .annotate( outgeom3857=Transform('geom', EPSG_3857), ) # Filter features layer_query = self._filter_on_property(layer_query, self.features_filter) layer_query = self._filter_on_geom_size(layer_query, self.layer.layer_geometry, pixel_width_x, pixel_width_y) if features_pks: layer_query = layer_query.filter(pk__in=list(features_pks)) # Lighten geometry layer_query = self._simplify(layer_query, pixel_width_x, pixel_width_y) # Seatbelt layer_query = self._limit(layer_query, self.features_limit) layer_raw_query, args = layer_query.query.sql_with_params() if self.properties_filter: filter = ', '.join([f"'{f}'" for f in self.properties_filter]) properties = f''' ( SELECT jsonb_object_agg(key, value) FROM jsonb_each(properties) WHERE key IN ({filter}) ) ''' elif self.properties_filter == []: properties = "'{}'::jsonb" else: properties = "properties" properties += " || json_build_object('_id', identifier)::jsonb" with connection.cursor() as cursor: sql_query = f''' WITH fullgeom AS ({layer_raw_query}), tilegeom AS ( SELECT ({properties}) AS properties, ST_AsMvtGeom( outgeom3857, ST_MakeEnvelope({xmin}, {ymin}, {xmax}, {ymax}, {EPSG_3857}), {self.TILE_WIDTH_PIXEL * self.EXTENT_RATIO}, {self.pixel_buffer * self.EXTENT_RATIO}, true) AS geometry FROM fullgeom) SELECT count(*) AS count, ST_AsMVT( tilegeom, CAST(%s AS text), {self.TILE_WIDTH_PIXEL * self.EXTENT_RATIO}, 'geometry' ) AS mvt FROM tilegeom ''' name = name if name else self.layer.name cursor.execute(sql_query, args + (name, )) row = cursor.fetchone() return row[0], row[1]
def get_queryset(self): pk = self.kwargs['pk'] trek = get_object_or_404(Trek.objects.existing(), pk=pk) return trek.information_desks.all().annotate( api_geom=Transform("geom", settings.API_SRID))
def get_extent(self, srid=3857): return self.features.annotate( geom_transformed=Transform('geom', srid) ).aggregate( extent=Extent('geom_transformed') )
def get_queryset(self): return Blade.objects.all().annotate( api_geom=Transform("signage__geom", settings.API_SRID))
def get_queryset(self): return super().get_queryset().annotate(_area=Area('geometry'), geom=Cast('geometry', output_field=models.GeometryField()), transformed=Transform('geom', 31370))
def get_queryset(self): return Trail.objects.existing().annotate( api_geom=Transform("geom", settings.API_SRID))
def get_queryset(self): return Path.objects.annotate( api_geom=Transform("geom", settings.API_SRID))
def get_queryset(self): qs = super(InformationDeskViewSet, self).get_queryset() if self.kwargs.get('type'): qs = qs.filter(type_id=self.kwargs['type']) qs = qs.annotate(api_geom=Transform("geom", settings.API_SRID)) return qs
def getfeature(request, service, wfs_version): context = {} propertyname = None featureversion = None maxfeatures = None typename = None featureid = None filtr = None bbox = None bbox_has_crs = False outputFormat = None resolution = None # A fallback value, if no features can be found crs = WGS84_CRS for key, value in request.GET.items(): low_key = key.lower() low_value = value.lower() if low_key == "propertyname": propertyname = low_value elif low_key == "featureversion": featureversion = low_value elif low_key == "maxfeatures": try: maxfeatures = int(low_value) except: return wfs_exception(request, "InvalidParameterValue", "maxfeatures", value) else: if maxfeatures < 1: return wfs_exception(request, "InvalidParameterValue", "maxfeatures", value) elif low_key == "typename": typename = low_value elif low_key == "featureid": featureid = low_value elif low_key == "filter": filtr = low_value elif low_key == "resolution": try: resolution = float(low_value) except: return wfs_exception(request, "InvalidParameterValue", "resolution", value) elif low_key == "bbox": # # See the following URL for all the gory details on the passed in bounding box: # # http://augusttown.blogspot.co.at/2010/08/mysterious-bbox-parameter-in-web.html bbox_values = low_value.split(",") if len(bbox_values) != 4 and (wfs_version == "1.0.0" or len(bbox_values) != 5): return wfs_exception(request, "InvalidParameterValue", "bbox", value) try: bbox_has_crs = len(bbox_values) == 5 bbox_crs = CRS(bbox_values[4]) if bbox_has_crs else crs if bbox_crs.crsid == "CRS84": # we and GeoDjango operate in longitude/latitude mode, so ban CRS84 bbox = Polygon.from_bbox( (float(bbox_values[1]), float(bbox_values[0]), float(bbox_values[3]), float(bbox_values[2]))) bbox_crs = WGS84_CRS else: bbox = Polygon.from_bbox( (float(bbox_values[0]), float(bbox_values[1]), float(bbox_values[2]), float(bbox_values[3]))) bbox.set_srid(bbox_crs.srid) except: return wfs_exception(request, "InvalidParameterValue", "maxfeatures", value) elif low_key == "srsname": try: crs = CRS(low_value) if crs.crsid == "CRS84": # we and GeoDjango operate in longitude/latitude mode, so ban CRS84 crs = WGS84_CRS except: return wfs_exception(request, "InvalidParameterValue", "maxfeatures", value) # This is for the case, that srsname is hit after the bbox parameter above if bbox and not bbox_has_crs: bbox.set_srid(crs.srid) elif low_key == "filter": filtr = low_value elif low_key == "outputformat": if low_value in ALL_JSON_OUTPUT_FORMATS: outputFormat = JSON_OUTPUT_FORMAT elif low_value in ALL_XML_OUTPUT_FORMATS: outputFormat = XML_OUTPUT_FORMAT else: return wfs_exception(request, "InvalidParameterValue", "outputformat", value) if propertyname is not None: raise NotImplementedError if featureversion is not None: raise NotImplementedError if filtr is not None: raise NotImplementedError result_bbox = None # If FeatureID is present we return every feature on the list of ID's if featureid is not None: feature_list = [] # we assume every feature is identified by its Featuretype name + its object ID like "name.id" for feature in featureid.split(","): try: ftname, fid = get_feature_from_parameter(feature) except ValueError: return wfs_exception(request, "InvalidParameterValue", "featureid", feature) try: ft = service.featuretype_set.get(name=ftname) ft_crs = CRS(ft.srs) try: geom_field = ft.find_first_geometry_field() if geom_field is None: return wfs_exception(request, "NoGeometryField", "feature") flter = json.loads(ft.query) objs = ft.model.model_class().objects if bbox: bbox_args = {geom_field + "__bboverlaps": bbox} objs = objs.filter(**bbox_args) if crs.srid != ft_crs.srid: objs = objs.annotate( xform=Transform(geom_field, crs.srid)) geom_field = "xform" if outputFormat == JSON_OUTPUT_FORMAT: objs = objs.annotate(geojson=AsGeoJSON(geom_field)) else: objs = objs.annotate(gml=AsGML(geom_field)) if flter: objs = objs.filter(**flter) f = objs.filter(id=fid) bb_res = f.aggregate(Extent(geom_field))[geom_field + '__extent'] if log.getEffectiveLevel() <= logging.DEBUG: log.debug("Bounding box for feature [%s] is [%s]" % (feature, bb_res)) if result_bbox is None: result_bbox = bb_res else: result_bbox = (min(result_bbox[0], bb_res[0]), min(result_bbox[1], bb_res[1]), max(result_bbox[2], bb_res[2]), max(result_bbox[3], bb_res[3])) feature_list.append((ft, f[0])) except: log.exception("caught exception in request [%s %s?%s]", request.method, request.path, request.environ['QUERY_STRING']) return wfs_exception(request, "MalformedJSONQuery", "query") except FeatureType.DoesNotExist: return wfs_exception(request, "InvalidParameterValue", "featureid", feature) # If FeatureID isn't present we rely on TypeName and return every feature present it the requested FeatureTypes elif typename is not None: feature_list = type_feature_iter() for typen in typename.split(","): try: ft = service.featuretype_set.get(name__iexact=typen) ft_crs = CRS(ft.srs) except FeatureType.DoesNotExist: return wfs_exception(request, "InvalidParameterValue", "typename", typen) try: geom_field = ft.find_first_geometry_field() if geom_field is None: return wfs_exception(request, "NoGeometryField", "feature") flter = json.loads(ft.query) objs = ft.model.model_class().objects if bbox: bbox_args = {geom_field + "__bboverlaps": bbox} objs = objs.filter(**bbox_args) if crs.srid != ft_crs.srid: objs = objs.annotate(xform=Transform(geom_field, crs.srid)) geom_field = "xform" if outputFormat == JSON_OUTPUT_FORMAT: objs = objs.annotate(geojson=AsGeoJSON(geom_field)) else: objs = objs.annotate(gml=AsGML(geom_field)) if flter: objs = objs.filter(**flter) if resolution is not None: res_flter = ft.resolutionfilter_set.filter( min_resolution__lte=resolution).order_by( "-min_resolution").first() if res_flter: log.debug( "Applying extra filter [%s] with condition [%s] for resolution [%f]" % (res_flter, res_flter.query, resolution)) res_flter_parsed = json.loads(res_flter.query) objs = objs.filter(**res_flter_parsed) bb_res = objs.aggregate(Extent(geom_field))[geom_field + '__extent'] if log.getEffectiveLevel() <= logging.DEBUG: log.debug("Bounding box for feature type [%s] is [%s]" % (typen, bb_res)) if result_bbox is None: result_bbox = bb_res else: result_bbox = (min(result_bbox[0], bb_res[0]), min(result_bbox[1], bb_res[1]), max(result_bbox[2], bb_res[2]), max(result_bbox[3], bb_res[3])) feature_list.add_type_with_features(ft, objs) except: log.exception("caught exception in request [%s %s?%s]", request.method, request.path, request.environ['QUERY_STRING']) return wfs_exception(request, "MalformedJSONQuery", "query") else: return wfs_exception(request, "MissingParameter", "typename") if outputFormat == JSON_OUTPUT_FORMAT: return StreamingHttpResponse(streaming_content=GeoJsonIterator( service.id, crs, result_bbox, feature_list), content_type="application/json") else: context['features'] = feature_list if result_bbox: context['bbox0'] = result_bbox[0] context['bbox1'] = result_bbox[1] context['bbox2'] = result_bbox[2] context['bbox3'] = result_bbox[3] context['crs'] = crs context['version'] = wfs_version context[ 'wfs_path'] = "1.0.0/WFS-basic.xsd" if wfs_version == "1.0.0" else "1.1.0/wfs.xsd" return render(request, 'getFeature.xml', context, content_type="text/xml")
def get_queryset(self): return Infrastructure.objects.existing().filter(published=True).annotate(api_geom=Transform("geom", settings.API_SRID))
def get_queryset(self): return Service.objects.existing().filter( type__published=True).annotate( api_geom=Transform("geom", settings.API_SRID))
def getfeature(request, service, wfs_version): context = {} propertyname = None featureversion = None maxfeatures = None typename = None featureid = None filtr = None bbox = None bbox_has_crs = False outputFormat = None resolution = None precision = None # A fallback value, if no features can be found crs = WGS84_CRS for key, value in request.GET.items(): low_key = key.lower() low_value = value.lower() if low_key == "propertyname": propertyname = low_value elif low_key == "featureversion": featureversion = low_value elif low_key == "maxfeatures": try: maxfeatures = int(low_value) except: return wfs_exception(request, "InvalidParameterValue", "maxfeatures", value) else: if maxfeatures < 1: return wfs_exception(request, "InvalidParameterValue", "maxfeatures", value) elif low_key == "typename": typename = low_value elif low_key == "featureid": featureid = low_value elif low_key == "filter": filtr = low_value elif low_key == "resolution": try: resolution = float(low_value) except: return wfs_exception(request, "InvalidParameterValue", "resolution", value) elif low_key == "precision": try: precision = float(low_value) except: return wfs_exception(request, "InvalidParameterValue", "precision", value) elif low_key == "bbox": # # See the following URL for all the gory details on the passed in bounding box: # # http://augusttown.blogspot.co.at/2010/08/mysterious-bbox-parameter-in-web.html bbox_values = low_value.split(",") if len(bbox_values) != 4 and (wfs_version == "1.0.0" or len(bbox_values) != 5): return wfs_exception(request, "InvalidParameterValue", "bbox", value) try: bbox_has_crs = len(bbox_values) == 5 bbox_crs = CRS(bbox_values[4]) if bbox_has_crs else crs if bbox_crs.crsid == "CRS84": # we and GeoDjango operate in longitude/latitude mode, so ban CRS84 bbox = Polygon.from_bbox( (float(bbox_values[1]), float(bbox_values[0]), float(bbox_values[3]), float(bbox_values[2]))) bbox_crs = WGS84_CRS else: bbox = Polygon.from_bbox( (float(bbox_values[0]), float(bbox_values[1]), float(bbox_values[2]), float(bbox_values[3]))) bbox.set_srid(bbox_crs.srid) except: return wfs_exception(request, "InvalidParameterValue", "bbox", value) elif low_key == "srsname": try: crs = CRS(low_value) if crs.crsid == "CRS84": # we and GeoDjango operate in longitude/latitude mode, so ban CRS84 crs = WGS84_CRS except: return wfs_exception(request, "InvalidParameterValue", "maxfeatures", value) # This is for the case, that srsname is hit after the bbox parameter above if bbox and not bbox_has_crs: bbox.set_srid(crs.srid) elif low_key == "filter": filtr = low_value elif low_key == "outputformat": if low_value in ALL_JSON_OUTPUT_FORMATS: outputFormat = JSON_OUTPUT_FORMAT elif low_value in ALL_XML_OUTPUT_FORMATS: outputFormat = XML_OUTPUT_FORMAT else: return wfs_exception(request, "InvalidParameterValue", "outputformat", value) if propertyname is not None: raise NotImplementedError if featureversion is not None: raise NotImplementedError if filtr is not None: raise NotImplementedError result_bbox = None closeable = None try: # If FeatureID is present we return every feature on the list of ID's if featureid is not None: feature_list = [] # we assume every feature is identified by its Featuretype name + its object ID like "name.id" for feature in featureid.split(","): try: ftname, fid = get_feature_from_parameter(feature) except ValueError: return wfs_exception(request, "InvalidParameterValue", "featureid", feature) try: ft = service.featuretype_set.get(name=ftname) ft_crs = CRS(ft.srs) try: if ft.model is None: # GML output of raw results not yet implemented if outputFormat != JSON_OUTPUT_FORMAT: raise NotImplementedError # prepare SQL statement select = parse_single( preprocess_query(ft.query, resolution, precision, bbox)) identifiers = get_identifiers(select) shape = find_identifier(identifiers, "shape") idi = find_identifier(identifiers, "id") # replace shape by ST_Simplify(shape,%s) if precision is not None: simplified = build_function_call( "ST_Simplify", shape, 1, True) replace_identifier(identifiers, shape, simplified) # add restriction id=%s add_condition(select, build_comparison(idi, "=")) sql = str(select) if log.getEffectiveLevel() <= logging.DEBUG: log.debug( "Final SQL for feature [%s] is [%s]" % (feature, sql)) # raw SQL result set with connection.cursor() as cur: if precision is None: cur.execute(sql, (fid, )) else: cur.execute(sql, (precision, fid)) row = cur.fetchone() feature = RawFeature(cur.description, row, crs.srid) if feature.geometry is None: return wfs_exception( request, "NoGeometryField", "feature") feature_list.append((ft, feature)) else: # django model based result set. geom_field = ft.find_first_geometry_field() if geom_field is None: return wfs_exception(request, "NoGeometryField", "feature") flter = parse_query(ft.query) objs = ft.model.model_class().objects if flter: objs = objs.filter(**flter) if bbox: bbox_args = {geom_field + "__bboverlaps": bbox} objs = objs.filter(**bbox_args) objs = objs.filter(id=fid) if crs.srid != ft_crs.srid: objs = objs.annotate( xform=Transform(geom_field, crs.srid)) geom_field = "xform" bb_res = objs.aggregate( Extent(geom_field))[geom_field + '__extent'] if log.getEffectiveLevel() <= logging.DEBUG: log.debug( "Bounding box for feature [%s] is [%s]" % (feature, bb_res)) if result_bbox is None: result_bbox = bb_res else: result_bbox = (min(result_bbox[0], bb_res[0]), min(result_bbox[1], bb_res[1]), max(result_bbox[2], bb_res[2]), max(result_bbox[3], bb_res[3])) if outputFormat == XML_OUTPUT_FORMAT: objs = objs.annotate(gml=AsGML(geom_field)) f = objs.first() if f is None: log.warning("Feature with ID [%s] not found." % feature) else: if outputFormat == JSON_OUTPUT_FORMAT: feature_list.append( (ft, DjangoFeature(ft, objs[0], precision))) else: feature_list.append((ft, objs[0])) except: log.exception("caught exception in request [%s %s?%s]", request.method, request.path, request.environ['QUERY_STRING']) return wfs_exception(request, "MalformedJSONQuery", "query") except FeatureType.DoesNotExist: return wfs_exception(request, "InvalidParameterValue", "featureid", feature) # If FeatureID isn't present we rely on TypeName and return every feature present it the requested FeatureTypes elif typename is not None: feature_list = type_feature_iter( outputFormat != JSON_OUTPUT_FORMAT, crs.srid, precision) closeable = feature_list for typen in typename.split(","): try: ft = service.featuretype_set.get(name__iexact=typen) ft_crs = CRS(ft.srs) except FeatureType.DoesNotExist: return wfs_exception(request, "InvalidParameterValue", "typename", typen) if ft.model is None: # raw SQL result set # GML output of raw results not yet implemented if outputFormat != JSON_OUTPUT_FORMAT: raise NotImplementedError # prepare SQL statement select = parse_single( preprocess_query(ft.query, resolution, precision, bbox)) identifiers = get_identifiers(select) shape = find_identifier(identifiers, "shape") idi = find_identifier(identifiers, "id") # parameters of SQL query params = [] # replace shape by ST_Simplify(shape,%s) if precision is not None: simplified = build_function_call( "ST_Simplify", shape, 1, True) replace_identifier(identifiers, shape, simplified) params.append(precision) if resolution is not None: res_flter = ft.resolutionfilter_set.filter( min_resolution__lte=resolution).order_by( "-min_resolution").first() if res_flter: if log.getEffectiveLevel() <= logging.DEBUG: log.debug( "Applying extra filter [%s] with condition [%s] for resolution [%f]" % (res_flter, res_flter.query, resolution)) res_flter_parsed = parse_single(res_flter.query) add_condition(select, res_flter_parsed) if bbox is not None: if ft.fields: if ft.fields != "{nobbox}": add_condition( select, build_function_call( "ST_Intersects", ft.fields, 1)) else: add_condition( select, build_function_call("ST_Intersects", shape, 1)) params.append(bbox.hexewkb.decode("utf-8")) sql = str(select) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("Final SQL for feature [%s] is [%s]" % (ft.name, sql)) cur = connection.cursor() try: cur.execute(sql, params) has_geometry = False for colinfo in cur.description: if _is_geom_column(colinfo): has_geometry = True break if not has_geometry: return wfs_exception(request, "NoGeometryField", "feature") feature_list.add_type_with_features(ft, cur) except: cur.close() log.exception("caught exception in request [%s %s?%s]", request.method, request.path, request.environ['QUERY_STRING']) return wfs_exception(request, "MalformedJSONQuery", "query") else: try: geom_field = ft.find_first_geometry_field() if geom_field is None: return wfs_exception(request, "NoGeometryField", "feature") flter = parse_query(ft.query) objs = ft.model.model_class().objects if flter: objs = objs.filter(**flter) if resolution is not None: res_flter = ft.resolutionfilter_set.filter( min_resolution__lte=resolution).order_by( "-min_resolution").first() if res_flter: log.debug( "Applying extra filter [%s] with condition [%s] for resolution [%f]" % (res_flter, res_flter.query, resolution)) res_flter_parsed = parse_query(res_flter.query) objs = objs.filter(**res_flter_parsed) if bbox: bbox_args = {geom_field + "__bboverlaps": bbox} objs = objs.filter(**bbox_args) if crs.srid != ft_crs.srid: objs = objs.annotate( xform=Transform(geom_field, crs.srid)) geom_field = "xform" bb_res = objs.aggregate( Extent(geom_field))[geom_field + '__extent'] if log.getEffectiveLevel() <= logging.DEBUG: log.debug( "Bounding box for feature type [%s] is [%s]" % (typen, bb_res)) if result_bbox is None: result_bbox = bb_res else: result_bbox = (min(result_bbox[0], bb_res[0]), min(result_bbox[1], bb_res[1]), max(result_bbox[2], bb_res[2]), max(result_bbox[3], bb_res[3])) if outputFormat == XML_OUTPUT_FORMAT: objs = objs.annotate(gml=AsGML(geom_field)) feature_list.add_type_with_features(ft, objs) except: log.exception("caught exception in request [%s %s?%s]", request.method, request.path, request.environ['QUERY_STRING']) return wfs_exception(request, "MalformedJSONQuery", "query") else: return wfs_exception(request, "MissingParameter", "typename") if outputFormat == JSON_OUTPUT_FORMAT: ret = StreamingHttpResponse(streaming_content=GeoJsonIterator( service.id, crs, result_bbox, feature_list), content_type="application/json") else: context['features'] = feature_list if result_bbox: context['bbox0'] = result_bbox[0] context['bbox1'] = result_bbox[1] context['bbox2'] = result_bbox[2] context['bbox3'] = result_bbox[3] context['crs'] = crs context['version'] = wfs_version context[ 'wfs_path'] = "1.0.0/WFS-basic.xsd" if wfs_version == "1.0.0" else "1.1.0/wfs.xsd" ret = render(request, 'getFeature.xml', context, content_type="text/xml") # Now, closing of resources is delegated to the HTTP response closeable = None return ret finally: if closeable is not None: try: closeable.close() except: log.exception( "Error closing left-over SQL cursor in WFS service.")
class FeatureViewSet(ProtectedViewSet): queryset = Feature.objects.all().annotate(geom=Transform( 'geometry', 4326)) # display coordinates in WGS84 serializer_class = FeatureSerializer
def calculate_area_field(apps, schema_editor): SpatialUnit = apps.get_model('spatial', 'SpatialUnit') SpatialUnit.objects.exclude(geometry=None).extra( where=["geometrytype(geometry) LIKE 'POLYGON'"]).update( area=Area(Transform('geometry', 3857)))