def area_intersect(query_type, title, request, area_id, format): area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area if not area.polygons.count(): return output_error(format, 'No polygons found', 404) generation = Generation.objects.current() args = { 'generation_low__lte': generation, 'generation_high__gte': generation, } type = request.REQUEST.get('type', '') if ',' in type: args['type__code__in'] = type.split(',') elif type: args['type__code'] = type elif area.type.code in ('EUR'): args['type__code'] = area.type.code set_timeout(format) try: areas = list(Area.objects.intersect(query_type, area).filter(**args).distinct()) areas = add_codes(areas) except QueryCanceledError: return output_error(format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500) except DatabaseError, e: # Django 1.2+ catches QueryCanceledError and throws its own DatabaseError instead if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error(format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500)
def area_polygon(request, srid='', area_id='', format='kml'): if not srid and hasattr(countries, 'area_code_lookup'): resp = countries.area_code_lookup(area_id, format) if resp: return resp if not re.match('\d+$', area_id): return output_error(format, 'Bad area ID specified', 400) if not srid: srid = 4326 if format in ('kml', 'json', 'geojson') else settings.MAPIT_AREA_SRID srid = int(srid) area = get_object_or_404(Area, id=area_id) if isinstance(area, HttpResponse): return area all_areas = area.polygons.all() if len(all_areas) > 1: all_areas = all_areas.collect() elif len(all_areas) == 1: all_areas = all_areas[0].polygon else: return output_json({ 'error': 'No polygons found' }, code=404) if srid != settings.MAPIT_AREA_SRID: all_areas.transform(srid) try: simplify_tolerance = float(request.GET.get('simplify_tolerance', 0)) except: return output_error(format, 'Badly specified tolerance', 400) if simplify_tolerance: all_areas = all_areas.simplify(simplify_tolerance) if format=='kml': out = '''<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <Style id="transBluePoly"> <LineStyle> <color>70ff0000</color> <width>2</width> </LineStyle> <PolyStyle> <color>3dff5500</color> </PolyStyle> </Style> <Placemark> <styleUrl>#transBluePoly</styleUrl> <name>%s</name> %s </Placemark> </kml>''' % (escape(area.name), all_areas.kml) content_type = 'application/vnd.google-earth.kml+xml' elif format in ('json', 'geojson'): out = all_areas.json content_type = 'application/json' elif format=='wkt': out = all_areas.wkt content_type = 'text/plain' return HttpResponse(out, content_type='%s; charset=utf-8' % content_type)
def nearest(request, srid, x, y, format='json'): location = Point(float(x), float(y), srid=int(srid)) set_timeout(format) try: postcode = Postcode.objects.filter(location__distance_gte=( location, D(mi=0) )).distance(location).order_by('distance')[0] except QueryCanceledError: return output_error(format, 'That query was taking too long to compute.', 500) except DatabaseError, e: if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error(format, 'That query was taking too long to compute.', 500)
def area_intersect(query_type, title, request, area_id, format): area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area all_areas = area.polygons.all() if len(all_areas) > 1: all_areas = all_areas.collect() elif len(all_areas) == 1: all_areas = all_areas[0].polygon else: return output_error(format, 'No polygons found', 404) generation = Generation.objects.current() args = { 'generation_low__lte': generation, 'generation_high__gte': generation, } type = request.REQUEST.get('type', '') if ',' in type: args['type__in'] = type.split(',') elif type: args['type'] = type elif area.type in ('EUR'): args['type'] = area.type if isinstance(query_type, list): or_queries = [ Q(**{'polygons__polygon__%s' % t: all_areas}) for t in query_type ] areas = Area.objects.exclude(id=area.id).filter(**args) areas = areas.filter(reduce(operator.or_, or_queries)) elif len(all_areas) == 1: areas = Area.objects.intersect(query_type, area) areas = areas.exclude(id=area.id).filter(**args) else: areas = Area.objects.exclude(id=area.id).filter(**args) areas = areas.filter(**{'polygons__polygon__%s' % query_type : all_areas }) areas = areas.distinct() set_timeout(format) try: if format == 'html': return output_html(request, title % ('<a href="/area/%d.html">%s</a>' % (area.id, area.name)), areas, norobots=True ) return output_json( dict( (a.id, a.as_dict() ) for a in areas ) ) except QueryCanceledError: return output_error(format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500)
def nearest(request, srid, x, y, format='json'): location = Point(float(x), float(y), srid=int(srid)) set_timeout(format) try: postcode = Postcode.objects.filter( location__distance_gte=(location, D( mi=0))).distance(location).order_by('distance')[0] except QueryCanceledError: return output_error(format, 'That query was taking too long to compute.', 500) except DatabaseError, e: if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error(format, 'That query was taking too long to compute.', 500)
def area_polygon(request, srid='', area_id='', format='kml'): if not srid and hasattr(countries, 'area_code_lookup'): resp = countries.area_code_lookup(area_id, format) if resp: return resp if not re.match('\d+$', area_id): return output_error(format, 'Bad area ID specified', 400) if not srid: srid = 4326 if format in ('kml', 'json', 'geojson') else settings.MAPIT_AREA_SRID srid = int(srid) area = get_object_or_404(Area, id=area_id) if isinstance(area, HttpResponse): return area all_areas = area.polygons.all() if len(all_areas) > 1: all_areas = all_areas.collect() elif len(all_areas) == 1: all_areas = all_areas[0].polygon else: return output_json({'error': 'No polygons found'}, code=404) if srid != settings.MAPIT_AREA_SRID: all_areas.transform(srid) try: simplify_tolerance = float(request.GET.get('simplify_tolerance', 0)) except: return output_error(format, 'Badly specified tolerance', 400) if simplify_tolerance: all_areas = all_areas.simplify(simplify_tolerance) if format == 'kml': out = '''<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <Placemark> <name>%s</name> %s </Placemark> </kml>''' % (area.name, all_areas.kml) content_type = 'application/vnd.google-earth.kml+xml' elif format in ('json', 'geojson'): out = all_areas.json content_type = 'application/json' elif format == 'wkt': out = all_areas.wkt content_type = 'text/plain' return HttpResponse(out, content_type='%s; charset=utf-8' % content_type)
def example_postcode_for_area(request, area_id, format='json'): area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area try: pc = Postcode.objects.filter(areas=area).order_by()[0] except: set_timeout(format) try: pc = Postcode.objects.filter_by_area(area).order_by()[0] except QueryCanceledError: return output_error(format, 'That query was taking too long to compute.', 500) except DatabaseError, e: if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error(format, 'That query was taking too long to compute.', 500) except: pc = None
def area_intersect(query_type, title, request, area_id, format): area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area if not area.polygons.count(): return output_error(format, 'No polygons found', 404) generation = Generation.objects.current() args = { 'generation_low__lte': generation, 'generation_high__gte': generation, } type = request.REQUEST.get('type', '') if ',' in type: args['type__code__in'] = type.split(',') elif type: args['type__code'] = type elif area.type.code in ('EUR'): args['type__code'] = area.type.code set_timeout(format) areas = Area.objects.intersect( query_type, area).exclude(id=area.id).filter(**args).distinct() try: if format == 'html': return output_html(request, title % ('<a href="/area/%d.html">%s</a>' % (area.id, area.name)), areas, norobots=True) return output_json(dict((a.id, a.as_dict()) for a in areas)) except QueryCanceledError: return output_error( format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500) except DatabaseError, e: # Django 1.2+ catches QueryCanceledError and throws its own DatabaseError instead if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error( format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500)
def areas_by_point(request, srid, x, y, bb=False, format='json'): type = request.REQUEST.get('type', '') generation = request.REQUEST.get('generation', Generation.objects.current()) if not generation: generation = Generation.objects.current() location = Point(float(x), float(y), srid=int(srid)) gdal.UseExceptions() try: location.transform(settings.MAPIT_AREA_SRID, clone=True) except: return output_error(format, 'Point outside the area geometry', 400) method = 'box' if bb and bb != 'polygon' else 'polygon' args = { 'generation_low__lte': generation, 'generation_high__gte': generation } if ',' in type: args['type__code__in'] = type.split(',') elif type: args['type__code'] = type if type and method == 'polygon': args = dict(("area__%s" % k, v) for k, v in args.items()) # So this is odd. It doesn't matter if you specify types, PostGIS will # do the contains test on all the geometries matching the bounding-box # index, even if it could be much quicker to filter some out first # (ie. the EUR ones). args['polygon__bbcontains'] = location shapes = Geometry.objects.filter(**args).defer('polygon') areas = [] for shape in shapes: try: areas.append( Area.objects.get(polygons__id=shape.id, polygons__polygon__contains=location)) except: pass else: if method == 'box': args['polygons__polygon__bbcontains'] = location else: geoms = list( Geometry.objects.filter( polygon__contains=location).defer('polygon')) args['polygons__in'] = geoms areas = Area.objects.filter(**args) if format == 'html': return output_html(request, 'Areas containing (%s,%s)' % (x, y), areas) return output_json(dict((area.id, area.as_dict()) for area in areas))
def area_from_code(request, code_type, code_value, format='json'): generation = request.REQUEST.get('generation', Generation.objects.current()) if not generation: generation = Generation.objects.current() try: area = Area.objects.get(codes__type__code=code_type, codes__code=code_value, generation_low__lte=generation, generation_high__gte=generation) except Area.DoesNotExist, e: message = 'No areas were found that matched code %s = %s.' % (code_type, code_value) return output_error(format, message, 404)
def area_intersect(query_type, title, request, area_id, format): area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area if not area.polygons.count(): return output_error(format, 'No polygons found', 404) generation = Generation.objects.current() args = { 'generation_low__lte': generation, 'generation_high__gte': generation, } type = request.REQUEST.get('type', '') if ',' in type: args['type__code__in'] = type.split(',') elif type: args['type__code'] = type elif area.type.code in ('EUR'): args['type__code'] = area.type.code set_timeout(format) areas = Area.objects.intersect(query_type, area).exclude(id=area.id).filter(**args).distinct() try: if format == 'html': return output_html(request, title % ('<a href="%sarea/%d.html">%s</a>' % (reverse('mapit_index'), area.id, area.name)), areas, norobots=True ) return output_json( dict( (a.id, a.as_dict() ) for a in areas ) ) except QueryCanceledError: return output_error(format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500) except DatabaseError, e: # Django 1.2+ catches QueryCanceledError and throws its own DatabaseError instead if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error(format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500)
def area(request, area_id, format='json'): if re.match('\d\d([A-Z]{2}|[A-Z]{4}|[A-Z]{2}\d\d\d|[A-Z]|[A-Z]\d\d)$', area_id): area = get_object_or_404(Area, format=format, codes__type='ons', codes__code=area_id) elif re.match('[ENSW]\d{8}$', area_id): area = get_object_or_404(Area, format=format, codes__type='gss', codes__code=area_id) elif not re.match('\d+$', area_id): return output_error(format, 'Bad area ID specified', 400) else: area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area if format == 'html': return render(request, 'area.html', { 'area': area, 'show_geometry': (area.type not in ('EUR', 'SPE', 'WAE')) }) return output_json( area.as_dict() )
def area(request, area_id, format='json'): if hasattr(countries, 'area_code_lookup'): resp = countries.area_code_lookup(area_id, format) if resp: return resp if not re.match('\d+$', area_id): return output_error(format, 'Bad area ID specified', 400) area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area if format == 'html': return render(request, 'mapit/area.html', { 'area': area, 'show_geometry': (area.type.code not in ('EUR', 'SPE', 'WAE')) }) return output_json( area.as_dict() )
def example_postcode_for_area(request, area_id, legacy=False, format='json'): area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area try: pc = Postcode.objects.filter(areas=area).order_by()[0] except: set_timeout(format) try: pc = Postcode.objects.filter_by_area(area).order_by()[0] except QueryCanceledError: return output_error(format, 'That query was taking too long to compute.', 500) except: pc = None if pc: pc = pc.get_postcode_display() if format == 'html': return render_to_response('example-postcode.html', { 'area': area, 'postcode': pc }) return output_json(pc)
def areas_by_point(request, srid, x, y, bb=False, format='json'): type = request.REQUEST.get('type', '') generation = request.REQUEST.get('generation', Generation.objects.current()) if not generation: generation = Generation.objects.current() location = Point(float(x), float(y), srid=int(srid)) gdal.UseExceptions() try: location.transform(settings.MAPIT_AREA_SRID, clone=True) except: return output_error(format, 'Point outside the area geometry', 400) method = 'box' if bb and bb != 'polygon' else 'polygon' args = { 'generation_low__lte': generation, 'generation_high__gte': generation } if ',' in type: args['type__code__in'] = type.split(',') elif type: args['type__code'] = type if type and method == 'polygon': args = dict( ("area__%s" % k, v) for k, v in args.items() ) # So this is odd. It doesn't matter if you specify types, PostGIS will # do the contains test on all the geometries matching the bounding-box # index, even if it could be much quicker to filter some out first # (ie. the EUR ones). args['polygon__bbcontains'] = location shapes = Geometry.objects.filter(**args).defer('polygon') areas = [] for shape in shapes: try: areas.append( Area.objects.get(polygons__id=shape.id, polygons__polygon__contains=location) ) except: pass else: if method == 'box': args['polygons__polygon__bbcontains'] = location else: geoms = list(Geometry.objects.filter(polygon__contains=location).defer('polygon')) args['polygons__in'] = geoms areas = Area.objects.filter(**args) if format == 'html': return output_html(request, 'Areas containing (%s,%s)' % (x,y), areas) return output_json( dict( (area.id, area.as_dict() ) for area in areas ) )
def area(request, area_id, format='json'): if hasattr(countries, 'area_code_lookup'): resp = countries.area_code_lookup(area_id, format) if resp: return resp if not re.match('\d+$', area_id): return output_error(format, 'Bad area ID specified', 400) area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area if format == 'html': return render( request, 'mapit/area.html', { 'area': area, 'show_geometry': (area.type.code not in ('EUR', 'SPE', 'WAE')) }) return output_json(area.as_dict())
def partial_postcode(request, postcode, format='json'): postcode = re.sub('\s+', '', postcode.upper()) if is_valid_postcode(postcode): postcode = re.sub('\d[A-Z]{2}$', '', postcode) if not is_valid_partial_postcode(postcode): return bad_request(format, "Partial postcode '%s' is not valid." % postcode) try: postcode = Postcode( postcode = postcode, location = Postcode.objects.filter(postcode__startswith=postcode).collect().centroid ) except: return output_error(format, 'Postcode not found', 404) if format == 'html': return render_to_response('postcode.html', { 'postcode': postcode.as_dict(), 'json': '/postcode/partial/', }) return output_json(postcode.as_dict())
def area(request, area_id, format='json'): if hasattr(countries, 'area_code_lookup'): resp = countries.area_code_lookup(area_id, format) if resp: return resp if not re.match('\d+$', area_id): return output_error(format, 'Bad area ID specified', 400) area = get_object_or_404(Area, format=format, id=area_id) if isinstance(area, HttpResponse): return area codes = [] for code_type, code in sorted(area.all_codes.items()): code_link = None if code_type in ('osm', 'osm_rel'): code_link = 'http://www.openstreetmap.org/browse/relation/' + code elif code_type == 'osm_way': code_link = 'http://www.openstreetmap.org/browse/way/' + code codes.append((code_type, code, code_link)) # Sort any alternative names by the description of the name (the # English name of the language for global MapIt) and exclude the # default OSM name, since if that exists, it'll already be # displayed as the page title. names = Name.objects.filter(area=area).select_related() alternative_names = sorted((n.type.description, n.name) for n in names if n.type.code != "default") if format == 'html': return render(request, 'mapit/area.html', { 'area': area, 'codes': codes, 'alternative_names': alternative_names, 'show_geometry': (area.type.code not in ('EUR', 'SPE', 'WAE')) }) return output_json( area.as_dict(names) )
def partial_postcode(request, postcode, format='json'): postcode = re.sub('\s+', '', postcode.upper()) if is_valid_postcode(postcode): postcode = re.sub('\d[A-Z]{2}$', '', postcode) if not is_valid_partial_postcode(postcode): return bad_request(format, "Partial postcode '%s' is not valid." % postcode) try: postcode = Postcode( postcode=postcode, location=Postcode.objects.filter( postcode__startswith=postcode).extra( where=['length(postcode) = %d' % (len(postcode) + 3)]).collect().centroid) except: return output_error(format, 'Postcode not found', 404) if format == 'html': return render_to_response('mapit/postcode.html', { 'postcode': postcode.as_dict(), 'json': '/postcode/partial/', }) return output_json(postcode.as_dict())
def form_submitted(request): pc = request.POST.get('pc', None) if not request.method == 'POST' or not pc: return redirect('/') return redirect('mapit.views.postcodes.postcode', postcode=pc, format='html') @ratelimit(minutes=3, requests=100) def nearest(request, srid, x, y, format='json'): location = Point(float(x), float(y), srid=int(srid)) set_timeout(format) try: postcode = Postcode.objects.filter(location__distance_gte=( location, D(mi=0) )).distance(location).order_by('distance')[0] except QueryCanceledError: return output_error(format, 'That query was taking too long to compute.', 500) except DatabaseError, e: if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error(format, 'That query was taking too long to compute.', 500) except: return output_error(format, 'No postcode found near %s,%s (%s)' % (x, y, srid), 404) if format == 'html': return render_to_response('mapit/postcode.html', { 'postcode': postcode.as_dict(), 'json': '/postcode/', }) return output_json({ 'postcode': postcode.as_dict(), })
return output_json(dict((a.id, a.as_dict()) for a in areas)) except QueryCanceledError: return output_error( format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500) except DatabaseError, e: # Django 1.2+ catches QueryCanceledError and throws its own DatabaseError instead if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error( format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500) except InternalError: return output_error( format, 'There was an internal error performing that query.', 500) @ratelimit(minutes=3, requests=100) def area_touches(request, area_id, format='json'): return area_intersect('touches', 'Areas touching %s', request, area_id, format) @ratelimit(minutes=3, requests=100) def area_overlaps(request, area_id, format='json'): return area_intersect('overlaps', 'Areas overlapping %s', request, area_id, format) @ratelimit(minutes=3, requests=100)
def bad_request(format, message): return output_error(format, message, 400)
try: if format == 'html': return output_html(request, title % ('<a href="%sarea/%d.html">%s</a>' % (reverse('mapit_index'), area.id, area.name)), areas, norobots=True ) return output_json( dict( (a.id, a.as_dict() ) for a in areas ) ) except QueryCanceledError: return output_error(format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500) except DatabaseError, e: # Django 1.2+ catches QueryCanceledError and throws its own DatabaseError instead if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error(format, 'That query was taking too long to compute - try restricting to a specific type, if you weren\'t already doing so.', 500) except InternalError: return output_error(format, 'There was an internal error performing that query.', 500) @ratelimit(minutes=3, requests=100) def area_touches(request, area_id, format='json'): return area_intersect('touches', 'Areas touching %s', request, area_id, format) @ratelimit(minutes=3, requests=100) def area_overlaps(request, area_id, format='json'): return area_intersect('overlaps', 'Areas overlapping %s', request, area_id, format) @ratelimit(minutes=3, requests=100) def area_covers(request, area_id, format='json'): return area_intersect('coveredby', 'Areas covered by %s', request, area_id, format) @ratelimit(minutes=3, requests=100) def area_coverlaps(request, area_id, format='json'):
def area_touches(request, area_id, format='json'): # XXX Exempt an error that throws a GEOS Exception if area_id == '2658': return output_error(format, 'There was an internal error performing that query.', 500) return area_intersect('touches', 'Areas touching %s', request, area_id, format)
@ratelimit(minutes=3, requests=100) def nearest(request, srid, x, y, format='json'): location = Point(float(x), float(y), srid=int(srid)) set_timeout(format) try: postcode = Postcode.objects.filter( location__distance_gte=(location, D( mi=0))).distance(location).order_by('distance')[0] except QueryCanceledError: return output_error(format, 'That query was taking too long to compute.', 500) except DatabaseError, e: if 'canceling statement due to statement timeout' not in e.args[0]: raise return output_error(format, 'That query was taking too long to compute.', 500) except: return output_error(format, 'No postcode found near %s,%s (%s)' % (x, y, srid), 404) if format == 'html': return render_to_response('mapit/postcode.html', { 'postcode': postcode.as_dict(), 'json': '/postcode/', }) return output_json({ 'postcode': postcode.as_dict(), })