python - lib - ¿Cómo mostrar datos usando Openlayers con OpenStreetMap en geodjango?
openlayers lib openlayers js (5)
Creo que su solución es viable y, probablemente, el enfoque más fácil. Simplemente personalice el javascript y use Django para inyectar sus puntos de datos a medida que se procesa la plantilla.
Si quería ser más elegante, podría tener una vista de Django que sirviera los puntos de datos como JSON (aplicación / json) y luego usar AJAX para devolver la llamada y recuperar los datos en función de los eventos que están sucediendo en el navegador. Si desea que su aplicación sea altamente interactiva más allá de lo que ofrece OpenLayers, podría valer la pena la complejidad adicional, pero por supuesto todo depende de las necesidades de su aplicación.
Tengo geodjango corriendo usando openlayers y OpenStreetMaps con la aplicación de administración.
Ahora quiero escribir algunas vistas para mostrar los datos. Básicamente, solo quiero agregar una lista de puntos (vistos en el administrador) al mapa.
Geodjango parece usar un archivo especial de openlayers.js para hacer magia en el administrador. ¿Hay una buena manera de interactuar con esto?
¿Cómo puedo escribir una vista / plantilla para visualizar los datos de geodjango en una ventana de mapa de calle abierta, como se ve en el administrador?
Por el momento, estoy investigando el archivo openlayers.js y la API que buscan una solución ''fácil''. (No tengo experiencia js así que esto toma algo de tiempo).
La forma actual en que puedo ver esto es agregar lo siguiente como plantilla y usar django para agregar el código necesario para mostrar los puntos. (Basado en el ejemplo aquí )
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Draw Feature Example</title>
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
<script type="text/javascript">
var map;
function init(){
map = new OpenLayers.Map(''map'');
var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: ''basic''} );
map.addLayer(layer);
/*
* Layer style
*/
// we want opaque external graphics and non-opaque internal graphics
var layer_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style[''default'']);
layer_style.fillOpacity = 0.2;
layer_style.graphicOpacity = 1;
/*
* Blue style
*/
var style_blue = OpenLayers.Util.extend({}, layer_style);
style_blue.strokeColor = "blue";
style_blue.fillColor = "blue";
style_blue.graphicName = "star";
style_blue.pointRadius = 10;
style_blue.strokeWidth = 3;
style_blue.rotation = 45;
style_blue.strokeLinecap = "butt";
var vectorLayer = new OpenLayers.Layer.Vector("Simple Geometry", {style: layer_style});
// create a point feature
var point = new OpenLayers.Geometry.Point(-111.04, 45.68);
var pointFeature = new OpenLayers.Feature.Vector(point,null,style_blue);
// Add additional points/features here via django
map.addLayer(vectorLayer);
map.setCenter(new OpenLayers.LonLat(point.x, point.y), 5);
vectorLayer.addFeatures([pointFeature]);
}
</script>
</head>
<body onload="init()">
<div id="map" class="smallmap"></div>
</body>
</html>
¿Es así como se hace, o hay una mejor manera?
Otra solución es crear un formulario que utilice el widget GeoDjango Admin.
Para hacer esto, yo:
Configurar un GeneratePolygonAdminClass:
class GeneratePolygonAdmin(admin.GeoModelAdmin):
list_filter=(''polygon'',)
list_display=(''object'', ''polygon'')
Donde se construye la forma:
geoAdmin=GeneratePolygonAdmin(ModelWithPolygonField, admin.site)
PolygonFormField=GeneratePolygon._meta.get_field(''Polygon'')
PolygonWidget=geoAdmin.get_map_widget(PolygonFormField)
Dict[''Polygon'']=forms.CharField(widget=PolygonWidget()) #In this case, I am creating a Dict to use for a dynamic form
Poblar el widget del formulario:
def SetupPolygonWidget(form, LayerName, MapFileName, DefaultPolygon=''''):
form.setData({''Polygon'':DefaultPolygon})
form.fields[''Polygon''].widget.params[''wms_layer'']=LayerName
form.fields[''Polygon''].widget.params[''wms_url'']=''/cgi-bin/mapserv?MAP='' + MapFileName
form.fields[''Polygon''].widget.params[''default_lon'']=-80.9
form.fields[''Polygon''].widget.params[''default_lat'']=33.7
form.fields[''Polygon''].widget.params[''default_zoom'']=11
form.fields[''Polygon''].widget.params[''wms_name'']=YOURWMSLayerName
form.fields[''Polygon''].widget.params[''map_width'']=800
form.fields[''Polygon''].widget.params[''map_height'']=600
form.fields[''Polygon''].widget.params[''map_srid'']=YOUR_SRID
form.fields[''Polygon''].widget.params[''modifiable'']=True
form.fields[''Polygon''].widget.params[''map_options'']={}
form.fields[''Polygon''].widget.params[''map_options''][''buffer''] = 0
return form
Basado en el código en: http://code.djangoproject.com/browser/django/branches/gis/django/contrib/gis/admin/options.py?rev=7980
Parece que puede usar la opción extra_js para incluir OpenStreetMap (no lo he probado).
Podría considerar usar FloppyForms . Al final, generalmente termino personalizando la solución para mis propias necesidades, pero es una buena forma de comenzar.
Mira este tutorial del proyecto geodjango-basic-apps:
http://code.google.com/p/geodjango-basic-apps/wiki/FOSS4GWorkshop
tal vez no tengas que hackear tu propio javascript todavía
Esto es bastante viejo, y yo no iría creando un hack de plantilla como estaba originalmente pensando. Ahora utilizaría leaflet.js con una solicitud de ajax a una vista django que devuelva geojson a una capa geojson de folleto.
Esto hace que el lado django sea muy fácil.
Muestra de la vista de Django:
# -*- coding: utf-8 -*-
''''''
''''''
import json
from django.http import HttpResponse, HttpResponseBadRequest
from django.contrib.gis.geos import Polygon
from models import ResultLayer, MyModel
def get_layer_polygons(request, layer_id):
"""
Return the polygons for the given bbox (bounding box)
"""
layer = ResultLayer.objects.get(id=layer_id)
bbox_raw = request.GET.get("bbox", None)
# Make sure the incoming bounding box is correctly formed!
bbox = None
if bbox_raw and bbox_raw.count(",") == 3:
bbox = [float(v) for v in bbox_raw.split(",")]
if not bbox:
msg = "Improperly formed or not given ''bbox'' querystring option, should be in the format ''?bbox=minlon,minlat,maxlon,maxlat''"
return HttpResponseBadRequest(msg)
bbox_poly = Polygon.from_bbox(bbox)
bbox_poly.srid = 900913 # google
bbox_poly.transform(layer.srid) # transform to the layer''s srid for querying
bin_size = int(bin_size)
# build vector polygons from bin
results = MyModel.objects.filter(layer=layer, poly__intersects=bbox_poly).transform(900913, field_name="poly")
geojson_data = []
for r in results:
# loading json in order to dump json list later
gjson = r.poly.geojson
py_gjson = json.loads(gjson)
geojson_data.append(py_gjson)
return HttpResponse(json.dumps(geojson_data), mimetype=''application/json'')