如何将 Geodjango 与 Google 地图 API 3 集成?

How to integrate Geodjango with Google Maps API 3?

我有一个包含多个字段的 geodjango 查询集,但只想使用 user_namelocation(一个点字段),我想将它们用作 google 地图中的标记 API 3.

请耐心等待,因为我不知道 Javascript,我有一系列问题。
以此作为新手的概念头脑风暴:

  1. 我的 SO 搜索提示我需要序列化查询集对象 到 JSON。我使用内置的序列化器模块转换为 JSON。
    我认为 JSON 对象在 views.py 中转换(让我们 称之为 json_data)。这些 JSON 对象是否存储在 PostGIS 数据库中?这不是多余的吗?

  2. 此外,我如何在 map.js (google 地图中引用它们 API 3) javascript 文件?
    我想(导入?link?)JSON 对象将它们显示为位置标记。

  3. 我想知道如何声明和迭代javascript变量 locations

For var(i=0;i< locations.length;i++){[
[json_data.user_name, json_data.point],
]

var map = new google.maps.Map(document.getElementById('map'), {
  center: new google.maps.LatLng(49.279504, -123.1162),
  zoom: 14,
  mapTypeId: google.maps.MapTypeId.ROADMAP
});
var infowindow = new google.maps.InfoWindow();
var marker, i;
for (i = 0; i < locations.length; i++) {
  marker = new google.maps.Marker({
    position: new google.maps.LatLng(locations[i][1], locations[i][2]),
    map: map,
    icon: 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'
  });
  google.maps.event.addListener(marker, 'click', (function(marker, i) {
    return function() {
      infowindow.setContent(locations[i][0]);
      infowindow.open(map, marker);
    }
  })(marker, i));
}

如果我以不必要的复杂方式完成简单任务,请指导我。

TL;DR

  1. 不,您所做的并不是多余的,这些答案中没有任何内容写入数据库。
  2. 您需要对 API 的端点进行 getJSON() 或类似调用才能访问数据。
  3. 您可以在第 2 步的调用中执行此操作并将其声明为列表。

您的想法基本正确,但还有改进的余地(因此下面的答案很长)。


答案:

前段时间看了一篇very good initiation tutorial on building a GIS application with geodjango and google maps。阅读它,它应该会给你一个很好的开始。

在您阅读之后,我们将采用一种稍微不同的方式,为您的前端留出更多空间(例如,使用 React 或任何想到的方式)。

后端:

  1. 使用 values() 查询集方法 JSON 创建视图以检索所需信息(user_namelocation)returns 字典列表。
    由于我们必须 JSON 验证一个列表,我们将使用 JsonResponse 并将其标记为不安全:

    from django.http import JsonResponse
    
    def my_view(request):
        resp = MyModel.objects.all().values('user_name', 'location')
        return JsonResponse(list(resp), safe=False)
    
  2. 添加端点以访问 urls.py 上的该视图:

    urlpatterns = [
        ...
        url(r'^my_endpoint/$', my_view, name='my_endpoint'),
        ...
    ]
    

    现在,每当我们访问 my_endpoint/ 时,我们都会得到数据库中每个对象的 user_namelocation 的 JSON 表示,如下所示:

    [
      {user_name: a_user, location: [lat, lng]},
      {user_name: another_user, location: [lat, lng]},
      ...
    ]
    

现在转到前端:

  1. 对 API 进行 getJSON()ajax() 或任何其他类型的调用,同时创建一个标记列表(接近什么@MoshFeu 建议):

    let map = new google.maps.Map(document.getElementById('map'), {
        center: new google.maps.LatLng(49.279504, -123.1162),
        zoom: 14,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    
    let markers = [];
    
    $.getJSON( "my_base_url/my_endpoint", function(data) {
        $.each(data, function() {
            markers.push(
                new google.maps.Marker({
                    position: {
                        lat: data['location'][0], 
                        lng: data['location'][1]
                    },
                    map: map,
                    icon: 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'
                })     
            );
        });
    });
    ...
    

我们差不多完成了!

您不需要对您的数据进行任何特殊的序列化。
您可以从您能想到的任何类型的前端查询数据,这为您提供了设计自由。

我的用例。我使用 django.contrib.gis (django.contrib.gis.db.models.PolygonField) 并需要用 Google 地图替换默认地图 + 更改默认地图坐标、缩放等

TL;DR

  • 我创建了一个名为 gis_addons 的新应用,其中包含要使用的自定义模板和小部件。
  • 我指示我的模型管理员(使用 formfield_overrides)使用我自己的地图小部件。

确保将 gis_addons 添加到 INSTALLED_APPS

文件:gis_addons/templates/gis_addons/openlayers_googlemaps.html

{% extends "gis/openlayers.html" %}

{% load i18n l10n %}

{% block base_layer %}
var base_layer = new ol.layer.Tile({
    source: new ol.source.XYZ({
        attributions: [new ol.Attribution({ html: '<a href=""></a>' })],
        maxZoom: 25,
        url: "http://mt0.google.com/vt/lyrs=r&hl=en&x={x}&y={y}&z={z}&s=Ga"
    })
});
{% endblock %}

{% block options %}var options = {
  base_layer: base_layer,
  geom_name: '{{ geom_type }}',
  id: '{{ id }}',
  map_id: '{{ id }}_map',
  map_options: map_options,
  map_srid: {{ map_srid|unlocalize }},
  name: '{{ name }}',
  default_lat: 53.2193835,
  default_lon: 6.5665018,
  default_zoom: 15
};
{% endblock %}

文件:gis_addons/widgets.py

from django.contrib.gis.forms.widgets import OpenLayersWidget

class GoogleMapsOpenLayersWidget(OpenLayersWidget):
    """Google Maps OpenLayer widget."""

    template_name = 'gis_addons/openlayers_googlemaps.html'

文件:my_app/models.py

from django.db import models
from django.contrib.gis.db import models as gis_models
from django.utils.translation import ugettext_lazy as _

class MyModel(models.Model):

    # ...

    coordinates = gis_models.PolygonField(
        verbose_name=_("Geo coordinates"),
    )

    def __str__(self):
        return self.name

文件:my_app/admin.py

from django.contrib import admin
from django.contrib.gis.db.models import PolygonField
from gis_addons.widgets import GoogleMapsOpenLayersWidget
from my_app.models import MyModel

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):

    # ...

    formfield_overrides = {
        PolygonField: {"widget": GoogleMapsOpenLayersWidget}
    }