2011-01-29 19 views
8

Ho un modulo Django in cui uno dei campi è uno TextInput per un indirizzo.Normalizzazione degli indirizzi in Django/Python

voglio per normalizzare i dati. Ad esempio:

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

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

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

O qualcosa del genere. Sto già usando geopy per la geocodifica. Forse questo potrebbe aiutare?

anche: Dove devo normalizzare? Nel modello di database o nella funzione di pulizia del campo modulo?

+0

Per quale paese/paesi? – payne

+0

Ci dispiace: USA. Specificamente NYC. –

risposta

4

Il modo più affidabile per farlo è quello di utilizzare un servizio di verifica degli indirizzi bona-fide. Non solo standardizzerà (normalizzerà) i componenti dell'indirizzo in base agli standard USPS (vedere Publication 28) ma sarà anche certo che l'indirizzo è reale.

Divulgazione completa: lavoro per SmartyStreets, che fornisce proprio tale service. Ecco alcuni davvero semplice codice di esempio python che mostra come utilizzare il nostro servizio tramite una richiesta HTTP GET:

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

+0

Sto lavorando su una libreria che ha a che fare con gli indirizzi, e mentre SmartyStreets sembra un po 'costoso (anche se il livello gratuito è abbastanza generoso), e probabilmente aggiungerebbe un po' di latenza alla mia libreria (richiedendo un viaggio di andata e ritorno server), sembra un servizio davvero fantastico. Penso che potrei aggiungere supporto per questo. * Continuate così! * – bgw

+0

Grazie! Solo per quello che sai, siamo geo-distribuiti e le richieste vengono gestite nel data center più vicino alla posizione dell'utente, il che riduce la latenza. – mdwhatcott

2

Un'opzione consisterebbe nell'utilizzare Geopy per cercare l'indirizzo su qualcuno come Yahoo o Google Maps, che restituirà quindi l'indirizzo completo di quello (i) con cui lo abbinano. Potrebbe essere necessario controllare che i numeri degli appartamenti vengano troncati nell'indirizzo restituito (ad es. "221 Amsterdam Av # 330" che diventa "221 AMSTERDAM AVENUE"). Inoltre, riceverai anche le informazioni sulla città/stato/paese, che l'utente potrebbe avere anche abbreviato o errato.

Nel caso in cui vi siano più corrispondenze, è possibile chiedere all'utente un feedback su quale sia il loro indirizzo. In caso di assenza di corrispondenze, puoi anche far sapere all'utente, e possibilmente consentire comunque il salvataggio dell'indirizzo, a seconda dell'importanza di un indirizzo valido, e quanta fiducia hai messo nella validità dell'indirizzo-ricerca-fornitori.

Riguardo fare questo normalizzazione nella forma rispetto al modello, non so che cosa il preferito Django-modo di fare le cose è, ma la mia preferenza è nella forma, ad esempio:

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...') 

È potrebbe gettare questa funzione di ricerca nel modello (o qualche file helpers.py) nel caso in cui si desidera riutilizzarla in altre aree

+1

Parola di cautela, ho usato questi servizi e non sono eccessivamente accurati, specialmente con appartamenti e suddivisioni. Inoltre, sono molto difficili, se non impossibili, da utilizzare per elaborare grandi lotti. – Cerin

2

questo è come ho finito per affrontare questo (no pun intended):

### 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) 

Quindi utilizzo Place.display_address nei modelli. Ciò mi consente di mantenere i dati inviati dall'utente originale nel database senza modifiche e utilizzare solo display_address quando voglio una versione di visualizzazione normalizzata.

Aperto per commenti/suggerimenti.

4

Di recente ho creato un modulo street-address pitone, e il suo StreetAddressFormatter può essere utilizzata per normalizzare il proprio indirizzo.

Problemi correlati