2011-01-29 33 views
8

Tengo un formulario Django en el que uno de los campos es TextInput para una calle.Normalizar direcciones de calles en Django/Python

Quiero normalizar los datos. Por ejemplo:

>> normalize('420 East 24th St.') 
'420 E. 24th Street' 

>> normalize('221 Amsterdam Av') 
'221 Amsterdam Ave.' 

>> normalize('221 Amsterdam Avenue') 
'221 Amsterdam Ave.' 

O algo así. Ya estoy usando geopy para geocodificar. Tal vez esto podría ayudar?

También: ¿Dónde debo normalizar? En el modelo de base de datos o en la función de limpieza del campo de formulario?

+0

¿Para qué país/países? – payne

+0

Lo siento: EE. UU. Específicamente NYC. –

Respuesta

4

La manera más confiable de hacer esto es utilizar un servicio de verificación de dirección de buena fe. No solo estandarizará (normalizará) los componentes de la dirección según los estándares de USPS (ver Publication 28) sino que también estará seguro de que la dirección es real.

Divulgación completa: trabajo para SmartyStreets, que proporciona exactamente un service. Aquí hay algunos realmente sencillo código de ejemplo en Python que muestra cómo utilizar nuestro servicio a través de una petición HTTP GET:

https://github.com/smartystreets/LiveAddressSamples/blob/master/python/street-address.py

+0

Estoy trabajando en una biblioteca que tiene que tratar con direcciones, y aunque SmartyStreets parece un poco caro (aunque el nivel gratuito es bastante generoso), y probablemente agregaría un poco de latencia a mi biblioteca (que requiere un viaje de ida y vuelta a un servidor), parece un servicio bastante impresionante. Creo que podría agregarle soporte. * ¡Sigan con el buen trabajo! * – bgw

+0

¡Gracias! Solo para que lo sepa, estamos geo-distribuidos y las solicitudes se manejan en el centro de datos más cercano a la ubicación del usuario, lo que reduce la latencia. – mdwhatcott

2

Una opción sería utilizar Geopy para buscar la dirección en alguien como Yahoo o Google Maps, que luego devolverá la dirección completa de la (s) persona (s) con la que coinciden. Es posible que tenga que vigilar para ver si los números de apartamento se truncan en la dirección devuelta (por ejemplo, "221 Amsterdam Av # 330" que se convierte en "221 AMSTERDAM AVENUE"). Además, también obtendrá la información de la ciudad/estado/país, que el usuario también puede haber abreviado o mal escrito.

En el caso de que haya múltiples coincidencias, puede solicitar al usuario retroalimentación sobre cuál es su dirección. En el caso de que no haya coincidencias, también puede informar al usuario, y posiblemente permitir que la dirección se guarde de todos modos, dependiendo de la importancia de una dirección válida y de la confianza que deposite en la validez de los proveedores de búsqueda de direcciones.

En cuanto a la normalización de hacer esto en forma comparación con el modelo, no sé lo que el Django-forma preferida de hacer las cosas es, pero mi preferencia es en la forma, por ejemplo:

def clean(self): 
    # check address via some self-defined helper function 
    matches = my_helper_address_matcher(address, city, state, zip) 
    if not matches: 
     raise forms.ValidationError("Your address couldn't be found...") 
    elif len(matches) > 1: 
     # add javascript into error so the user can select 
     # the address that matches? maybe there is a cleaner way to do this 
     raise forms.ValidationError('Did you mean...') 

Usted podría lanzar esta función de búsqueda en el modelo (o algún archivo helpers.py) en caso de que quiera volver a utilizarlo en otras áreas

+1

Como advertencia, he utilizado estos servicios, y no son muy precisos, especialmente con apartamentos y subdivisiones. Además, son muy difíciles, si no imposibles, de utilizar para procesar grandes lotes. – Cerin

2

esto es como terminé frente a este (sin doble sentido):

### models.py ### 

def normalize_address_for_display(address): 

    display_address = string.capwords(address) 

    # Normalize Avenue 
    display_address = re.sub(r'\b(Avenue|Ave.)\b', 'Ave', display_address) 

    # Normalize Street 
    display_address = re.sub(r'\b(Street|St.)\b', 'St', display_address) 

    # ...and other rules... 

    return display_address 

class Store(models.Model): 

    name = models.CharField(max_length=32) 
    address = models.CharField(max_length=64) 
    city = models.CharField(max_length=32) 
    state = models.CharField(max_length=2) 
    zipcode = models.CharField(max_length=5) 

    @property 
    def display_address(self): 
     return normalize_address_for_display(self.address) 

Luego uso Place.display_address en plantillas. Esto me permite mantener los datos originales enviados por el usuario en la base de datos sin modificaciones y solo uso display_address cuando quiero una versión de visualización normalizada.

Abierto para comentarios/sugerencias.

4

he creado recientemente un módulo de street-address pitón, y su StreetAddressFormatter se puede utilizar para normalizar su dirección.

Cuestiones relacionadas