Question

I have a very simple Django form which consists of a single field - "address":

class AddressSearchForm(forms.Form):
    """
        A form that allows a user to enter an address to be geocoded
    """
    address = forms.CharField()

I probably do not even need to use a form, since I'm not saving this data - I'm just collecting it to use in a search. But, I want to perform validation:

def clean_address():
    data = self.cleaned_data
    g = geocoders.Google()
    try:
        place, (lat,lng) = g.geocode(data['address'])
    except (GQueryError):
        raise forms.ValidationError('Please enter a valid address')
    except (GeocoderResultError, GBadKeyError, GTooManyQueriesError):
        raise forms.ValidationError('There was an error geocoding your address. Please      try again')
    except:
        raise forms.ValidationError('An unknown error occured. Please try again')

In addition, I want to use this geocoded result to pass a Point object to my view:

from django.contrib.gis.geos import Point
point = Point(lng, lat)

My question is, how to pass both the address and the point data to my view? I could just pass the address and then re-geocode in the view, but that would be duplicating code. So, how to pass the point object from the form? Should I use a hidden field? Other suggestions? Thanks in advance.

Was it helpful?

Solution

I'm no django expert, but this is what I did:

 def clean_homeaddress(self):
        in_address = self.cleaned_data['homeaddress']        
        place, self.cleaned_data['homelocation'] = address_to_latlng(in_address, True)
        return place

oh, and by the way, have a look at the wrapper below. geocoders.Google doesn't handle unicode strings properly. There's a simple hack below which removes all non-ascii characters. I haven't had time to figure out better solution yet.

def address_to_latlng(address, return_address = False):
    """ returns GoeDjango POINT string value for given location (address)
        if return_address is true, it'll return 2-tuple: (address, point)
        otherwise it returns point
    """ 
    g = geocoders.Google()
    try:
        #TODO: not really replace, geocode should use unicode strings
        address = address.encode('ascii', 'replace')            
        place, latlng = g.geocode(address)            
    except Exception as e:            
        raise ValidationError(_(u"Incorrect location provided"))
    point = 'POINT(%f %f)' % tuple(reversed(latlng))
    if return_address:
        return (place, point)    
    return point

as requested, there's full code. this one will print the location to the output console, and it'll keep the "cleaned" (as returned by Google) address in the session, to display it to the user each time the form is displayed.

class GeoForm(forms.Form):
    address = forms.CharField()    

    def clean_address(self):
        in_address = self.cleaned_data['address']        
        place, self.cleaned_data['location'] = address_to_latlng(in_address, True)
        return place

class GeoView(FormView):
    form_class = GeoForm
    template_name = 'geoview.html'
    success_url = '/sandbox/geo'
    def get_initial(self):
        if '_address' in self.request.session:
            return {'address': self.request.session['_address']}
        return {}
    def form_valid(self,form):
        print form.cleaned_data['location']
        self.request.session['_address'] = form.cleaned_data['address']
        return super(GeoView, self).form_valid(form)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top