在表单提交时进行地址地理编码?

8 投票
5 回答
6264 浏览
提问于 2025-04-15 22:16

我正在努力理解Django的表单和它的工作方式。我想创建一个简单的网页表单,让用户输入一个地址,然后把这个地址进行地理编码(也就是转换成经纬度)并保存到数据库里。

我创建了一个地点模型:

class Location(models.Model):
    address = models.CharField(max_length=200)
    city = models.CharField(max_length=100)
    state = models.CharField(max_length=100, null=True)
    postal_code = models.CharField(max_length=100, null=True)
    country = models.CharField(max_length=100)
    latitude = models.DecimalField(max_digits=18, decimal_places=10, null=True)
    longitude = models.DecimalField(max_digits=18, decimal_places=10, null=True)

然后定义了一个表单:

class LocationForm(forms.ModelForm):
    class Meta:
        model = models.Location
        exclude = ('latitude','longitude')

在我的视图中,我使用form.save()来保存表单。这是有效的,可以把地址保存到数据库中。

我还创建了一个模块来进行地址的地理编码。我不太确定Django的标准做法是什么,但我想在保存表单之前,我需要先对地址进行地理编码,并设置经度和纬度。那么,在保存之前,我该如何设置经度和纬度呢?

5 个回答

2

你还可以使用 django.db.models.signals.pre_save 这个信号!

可以看看Django的信号文档,地址是 http://docs.djangoproject.com/en/dev/topics/signals/

3

关于Google地图API v3的更新:

import json
import urllib.parse
from decimal import Decimal

def save(self):
    if not self.lat or not self.lng:
        self.lat, self.lng = self.geocode(self.address)

    super(Location, self).save()

def geocode(self, address):
    address = urllib.parse.quote_plus(address)
    maps_api_url = "?".join([
        "http://maps.googleapis.com/maps/api/geocode/json",
        urllib.parse.urlencode({"address": address, "sensor": False})
    ])
    response = urllib.urlopen(maps_api_url)
    data = json.loads(response.read().decode('utf8'))

    if data['status'] == 'OK':
        lat = data['results'][0]['geometry']['location']['lat']
        lng = data['results'][0]['geometry']['location']['lng']
        return Decimal(lat), Decimal(lng)
8

你可以重写模型的保存方法。在保存数据之前,我会先进行地理编码。这是使用谷歌的API,但你可以根据需要进行修改。

import urllib

def save(self):
    location = "%s, %s, %s, %s" % (self.address, self.city, self.state, self.zip)

    if not self.latitude or not self.longitude:
        latlng = self.geocode(location)
        latlng = latlng.split(',')
        self.latitude = latlng[0]
        self.longitude = latlng[1]

    super(Marker, self).save()

def geocode(self, location):
    output = "csv"
    location = urllib.quote_plus(location)
    request = "http://maps.google.com/maps/geo?q=%s&output=%s&key=%s" % (location, output, settings.GOOGLE_API_KEY)
    data = urllib.urlopen(request).read()
    dlist = data.split(',')
    if dlist[0] == '200':
        return "%s,%s" % (dlist[2], dlist[3])
    else:
        return ','

撰写回答