【问题标题】:Geocoding an address on form submission?对表单提交的地址进行地理编码?
【发布时间】:2025-11-24 04:55:02
【问题描述】:

试图围绕 django 表单和 django 的做事方式。我想创建一个基本的 Web 表单,允许用户输入地址并将该地址进行地理编码并保存到数据库中。

我创建了一个 Location 模型:

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 的处理方式是什么,但我想在我看来,在保存表单之前,我需要对地址进行地理编码并设置纬度和经度。保存前如何设置经纬度?

【问题讨论】:

    标签: python django django-forms geocoding


    【解决方案1】:

    您可以覆盖模型的保存方法。我在保存之前对数据进行地理编码。这是使用googleapi,但可以进行相应的修改。

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

    【讨论】:

    • 非常感谢,我会试试这个并回复你。您如何看待 geocode() 返回元组或坐标对象而不是字符串?
    • 这是个好主意。在返回之前更好地打包数据会更干净。一般来说,我喜欢做这样的事情。由于我如何重构原始方程,我以这种方式离开了它。我一直在想 CSV 只是因为这就是它从谷歌返回的方式,但我喜欢你的想法。我将重构它以返回一个对象。
    • 以下 Google Maps API v3 更新。
    【解决方案2】:

    Google Maps 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)
    

    【讨论】:

      【解决方案3】:

      您也可以使用django.db.models.signals.pre_save-信号!

      查看 Django 的信号文档http://docs.djangoproject.com/en/dev/topics/signals/

      【讨论】:

        【解决方案4】:

        我正在做同样的事情 可能是紫杉正在寻找类似的东西强烈的文字

        # forms.py 
        from django.contrib.gis.utils import GeoIP
        
        
        class registerForm(forms.ModelForm): 
        class Meta:
            model=register
            fields = ('Availability', 'Status')
        
        def save(self,ip_address, *args, **kwargs):
            g = GeoIP()
            lat, lon = g.lat_lon(ip_address)
            user_location = super(registerForm, self).save(commit=False)
            user_location.latitude = lat
            user_location.longitude = lon
            user_location.save(*args, **kwargs)
        

        我的看法

            #views.py
            if request.method == "POST":
         ip_address=request.META['REMOTE_ADDR']
            rform = registerForm(data = request.POST)
            if rform.is_valid():
          register = rform.save(commit=False)
          register.user=request.user
             register.save(ip_address)
                return render_to_response('home.html')
        else:
            rform = registerForm() 
        return render_to_response('status_set.html',{'rform':rform}) 
        

        【讨论】:

          【解决方案5】:

          与其他答案类似:

          def geocode(address, city, state, zip_code):
              try:
                  location_param = urllib.request.quote("%s, %s, %s, %s" % (address, city, state, zip_code))
                  url_request = "http://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false" % location_param
                  result = requests.get(url_request)
                  data = result.json()
                  location = data['results'][0]['geometry']['location']
                  lat = location['lat']
                  lng = location['lng']
                  return lat, lng
              except Exception:
                  return None
          

          【讨论】:

          • 我收到“return lat, lng”的无效语法错误。我不知道为什么。