python 如何在 geodjango 中使用带有 OpenStreetMap 的 openlayers 显示数据?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/559431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:22:28  来源:igfitidea点击:

How to display data using openlayers with OpenStreetMap in geodjango?

pythonmappingopenlayersgeodjango

提问by monkut

I've got geodjango running using openlayersand OpenStreetMapswith the admin app.

我已经在管理应用程序中使用openlayersOpenStreetMaps运行 geodjango 。

Now I want to write some views to display the data. Basically, I just want to add a list of points (seen in the admin) to the map.

现在我想写一些视图来显示数据。基本上,我只想向地图添加一个点列表(在管理员中看到)。

Geodjango appears to use a specialopenlayers.jsfile to do it's magic in the admin. Is there a good way to interface with this?

Geodjango 似乎使用一个特殊的openlayers.js文件在管理中实现它的魔力。有什么好的方法可以与此交互吗?

How can I write a view/template to display the geodjango data on a open street map window, as is seen in the admin?

如何编写视图/模板以在打开的街道地图窗口上显示 geodjango 数据,如在管理员中看到的那样?

At the moment, I'm digging into the openlayers.jsfile and api looking for an 'easy' solution. (I don't have js experience so this is taking some time.)

目前,我正在深入研究openlayers.js文件和 api,以寻找“简单”的解决方案。(我没有 js 经验,所以这需要一些时间。)

The current way I can see to do this is add the following as a template, and use django to add the code needed to display the points. (Based on the example here)

我可以看到的当前方法是将以下内容添加为模板,并使用 django 添加显示点所需的代码。(基于这里的例子)

<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>

Is this how it's done, or is there a better way?

这是如何完成的,还是有更好的方法?

采纳答案by Joe Holloway

I think your solution is workable and probably the easiest approach. Just templatize the javascript and use Django to inject your data points as the template is rendered.

我认为您的解决方案是可行的,并且可能是最简单的方法。只需模板化 javascript 并在呈现模板时使用 Django 注入您的数据点。

If you wanted to get fancier, you could have a Django view that served up the data points as JSON (application/json) and then use AJAX to call back and retrieve the data based on events that are happening in the browser. If you want your application to be highly interactive above and beyond what OpenLayers provides, this might be worth the added complexity, but of course it all depends on the needs of your application.

如果您想变得更有趣,您可以拥有一个 Django 视图,将数据点作为 JSON (application/json) 提供,然后使用 AJAX 回调并根据浏览器中发生的事件检索数据。如果您希望您的应用程序具有超出 OpenLayers 提供的高度交互性,这可能值得增加复杂性,但当然这一切都取决于您的应用程序的需求。

回答by Gregory Roby

Another solution is to create a form that utilizes the GeoDjango Admin widget.

另一种解决方案是创建一个使用 GeoDjango Admin 小部件的表单。

To do this, I:

为此,我:

Setup a GeneratePolygonAdminClass:

设置一个 GeneratePolygonAdminClass:

class GeneratePolygonAdmin(admin.GeoModelAdmin):
    list_filter=('polygon',)
    list_display=('object', 'polygon')

Where the form is built:

在哪里构建表单:

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

Populating the widget of the form:

填充表单的小部件:

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

Based on the code at: http://code.djangoproject.com/browser/django/branches/gis/django/contrib/gis/admin/options.py?rev=7980

基于以下代码:http: //code.djangoproject.com/browser/django/branches/gis/django/contrib/gis/admin/options.py?rev=7980

It looks like you can use the extra_js option to include OpenStreetMap (I have not tested this).

看起来您可以使用 extra_js 选项来包含 OpenStreetMap (我尚未对此进行测试)。

回答by monkut

This is quite old, and I wouldn't go around creating a template hack as I originally was thinking. Now I would use leaflet.jswith an ajax request to a django view that returns geojson to a leaflet geojson layer.

这已经很老了,我不会像我最初想的那样四处创建模板黑客。现在我将使用leaflet.js和ajax 请求到django 视图,该视图将geojson 返回到传单geojson 层。

This makes the django side super easy.

这使得 django 方面变得非常简单。

Sample Django View:

示例 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')

回答by ivy

You could consider using FloppyForms. In the end, I usually end up customizing the solution to my own needs, but it's a nice way to get started.

您可以考虑使用FloppyForms。最后,我通常会根据自己的需要定制解决方案,但这是一个很好的入门方式。

回答by Anentropic

Checkout this tutorial from the geodjango-basic-apps project:
http://code.google.com/p/geodjango-basic-apps/wiki/FOSS4GWorkshop

从 geodjango-basic-apps 项目中查看本教程:http:
//code.google.com/p/geodjango-basic-apps/wiki/FOSS4GWorkshop

maybe you don't have to hack up your own javascript just yet

也许你还不需要修改你自己的 javascript