【问题标题】:Send GeoDjango queryset to template and consume with OpenLayers.js将 GeoDjango 查询集发送到模板并与 OpenLayers.js 一起使用
【发布时间】:2014-01-08 01:13:57
【问题描述】:

我最近一直在学习使用 GeoDjango,并且一直在学习一些教程以尝试了解所有内容是如何组合在一起的。我也是 GIS 新手,但对 Django 比较熟悉。

我一直在关注这个教程,如果不是有点过时的话,这很棒:https://code.google.com/p/geodjango-basic-apps/wiki/FOSS4GWorkshop

我已经到了第 8 节,尽可能地更新了 django 的东西,并试图绕过已弃用的 OpenLayers 的东西,但是我遇到了一些问题。

本教程包含以下代码来生成查询集并将其发送到 OpenLayers.js 使用的模板:

教程的view.py:

def ward(request, id):
     ward = get_object_or_404(Ward, pk=id)
     interesting_points = InterestingLocation.objects.filter(
          geometry__intersects=(ward.geometry))
     return render_to_response("ward.html", { 
      'ward': ward, 'interesting_points': interesting_points }) 

教程的 OpenLayers 代码(不完整):

 geojson_format = new OpenLayers.Format.GeoJSON()
    ward = geojson_format.read({{ ward.geometry.geojson|safe}})[0];
    // We mark it 'safe' so that Django doesn't escape the quotes.

    ward.attributes = { 'name': "{{ward.name}}", 'type': 'ward'}; 
    vectors = new OpenLayers.Layer.Vector("Data");
    vectors.addFeatures(ward);

我已经编写了以下代码,但我不断收到错误消息(js 控制台)“对象没有方法'replace'”。

我的观点.py

def interesting_area(request, iso3_id):
    iso3_id = iso3_id.upper()
    country = get_object_or_404(WorldBorder, iso3=iso3_id)
    interesting_points = InterestingLocation.objects.filter(
        geometry__intersects=(country.mpoly))
    return render_to_response("some_places.html", {
        'country': country,
        'interesting_points': interesting_points})

我的 openlayers.js 尝试

function map_init() {
      json_format = new OpenLayers.Format.GeoJSON();
      countryson = json_format.read({{country.mpoly.geojson|safe}})[0];
      countryson.attributes = {'name': "{{country.name}}",
                            'area': "{{country.area}}",
                            'population': "{{country.pop2005}}",
                             'type': 'country'};
      vectors = new OpenLayers.Layer.Vector("Data");
      vectors.addFeatures(countryson);
      var map = new OpenLayers.Map('map-container');
      var base_layer = new OpenLayers.Layer.OSM("Base Map", {
                 "tileOptions": { "crossOriginKeyword": null } 
      });
      map.addLayers([base_layer, vectors]);
      map.zoomToMaxExtent(countryson.geometry.getBounds());
     }

我相信错误在countryson = json_format.read({{country.mpoly.geojson|safe}})[0];这一行中

有谁知道如何发送模型对象并能够在模板端读取其 geometry.geojson 属性?我已经看到如何通过使用返回静态文件的视图/url 来做到这一点,但我希望能够通过将数据直接返回到模板来做到这一点。

脚注:我看到其他一些答案说要使用矢量格式,但似乎应该有一种方法可以在 GeoDjango 中本地执行此操作,但是通过我的谷歌搜索和搜索答案,我似乎无法找到人们通常如何做到这一点。

感谢您的帮助。

编辑:

我觉得有点傻,但是@sk1p 询问了我关于js traceback 的问题,当我查看它时,它告诉我负责错误的行如下:

map.zoomToMaxExtent(countryson.geometry.getBounds());

所以我删除了它并且错误消失了,但我仍然无法让我的地图渲染。我将继续查看返回的对象。

【问题讨论】:

  • 究竟是什么问题/问题?
  • 'enter' 键使它快速发布。用完整的问题编辑。
  • 你能获得那个js错误的回溯吗?另外,查看生成的 html/js:IIRC .geojson 不返回完整的 GeoJSON 对象,您可能需要查看 OpenLayers API 以查看它是否接受您传递的内容
  • 好的。明天上班的时候应该可以做。我在理解 OpenLayers API 时遇到了一些麻烦。我可能应该阅读他们是如何编写该方法的。谢谢。
  • 你可以使用geojson包形成一个合适的geojson并从django端发送,然后直接在地图上渲染。

标签: django openlayers gis geodjango


【解决方案1】:

经过大量的实验,我找到了一个可以在模板中渲染geojson的系统。我认为我的错误非常基本,并且来自于不理解实际的几何字段本身必须呈现为 geojson(并且可以从模板中访问)。

我也改用 Leaflet,因为它加载速度非常快,而且似乎有一个不错的 API。

我有一个程序可以导入 shapefile 并将它们分解为 Shapefile->Features->Attributes。这是受 Python for Geo-Spatial Development 一书的启发。相关模型如下所示:

models.py:

class Shapefile(models.Model):
    filename = models.CharField(max_length=255)
    srs_wkt = models.TextField()
    geom_type = models.CharField(max_length=50)

class Feature(models.Model):
    shapefile = models.ForeignKey(Shapefile)
    reference = models.CharField(max_length=100, blank=True)
    geom_point = models.PointField(srid=4326, blank=True, null=True)
    geom_multipoint = models.MultiPointField(srid=4326, blank=True, 
                                             null=True)
    geom_multilinestring = models.MultiLineStringField(srid=4326, 
                                                       blank=True, 
                                                       null=True)
    geom_multipolygon = models.MultiPolygonField(srid=4326, 
                                                 blank=True, 
                                                 null=True)
    geom_geometrycollection = models.GeometryCollectionField(srid=4326,
                                                             blank=True,
                                                             null=True)
    objects = models.GeoManager()

    def __str__(self):
        return "{}".format(self.id)

    ## need some method to return the geometry type this guy has.
    def _get_geometry(self):
        geoms = [self.geom_point, self.geom_multipoint,
                 self.geom_multilinestring, self.geom_multipolygon,
                 self.geom_geometrycollection]
        geom = next(filter(lambda x: x, geoms))
        return geom

    geometry = property(_get_geometry)

注意:因为我正在处理通用 shapefile,并且我以前不知道特征将具有什么样的几何形状,所以我在特征中包含了 geometry 属性以返回实际的几何字段和丢弃其他未使用的。我稍后会使用它从模板中访问几何的 geojson 方法。

在我看来,我会响应包含 shapefile id 的请求,并查询该 shapefile 中的功能。

views.py:

def view_shapefile(request, shapefile_id, 
               template_file='shape_editor/viewshapefile.html'):
    all_features = Feature.objects.filter(
                     shapefile__id=shapefile_id).select_related(
                          'shapefile')
    filename = all_features[0].shapefile.filename

    ### we need something to set the center of our map ###
    lon, lat = all_features[0].geometry.centroid.tuple
    temp_vars = {'features' : all_features,
                 'filename' : filename,
                 'lon': lon,
                 'lat' : lat}
    return render(request, template_file, temp_vars) 

我的模板使用 Leaflet 来处理返回的对象,如下所示:

function map_init(map_div) {
   var tileMapQuest = L.tileLayer('http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
 subdomains: ['otile1','otile2','otile3','otile4'],
 attribution: 'Map tiles by <a href="http://open.mapquestapi.com/">MapQuest</a>. Data &copy; by <a href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>.',
 maxZoom: 18
   });
   var map_layers = [tileMapQuest];
   var map = L.map('map-container', {
     center: [{{ lat }}, {{ lon }}],
     zoom: 10,
     layers: map_layers,
     worldCopyJump: false
   });
   {% if features %}
     {% for feat in features %}
       var feature = new L.geoJson({{ feat.geometry.geojson|safe }}).addTo(map);
     {% endfor %}
   {% endif %}
}

我不确定这是否对其他人有帮助,并且可能有更好的方法可以做到这一点,尤其是在我试图找出用于使地图居中的纬度和经度的情况下。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-07
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    • 2016-08-21
    • 1970-01-01
    • 2019-02-01
    相关资源
    最近更新 更多