规范化Django / Python中的街道地址

时间:2011-01-29 17:22:45

标签: python django django-models django-forms geopy

我有一个Django表单,其中一个字段是街道地址的TextInput

我想规范化数据。例如:

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

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

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

或类似的东西。我已经在使用geopy进行地理编码了。也许这可能会有所帮助?

另外:我应该在哪里正常化?在数据库模型中还是在表单字段的clean函数中?

4 个答案:

答案 0 :(得分:4)

最可靠的方法是使用真正的地址验证服务。它不仅会根据USPS标准对地址组件进行标准化(规范化)(参见Publication 28),而且您还可以确定该地址是真实的。

完全披露:我为SmartyStreets工作,它提供了这样的service。这是一些非常简单的python示例代码,展示了如何通过HTTP GET请求使用我们的服务:

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

答案 1 :(得分:4)

我最近创建了一个street-address python模块,其StreetAddressFormatter可用于规范化您的地址。

答案 2 :(得分:3)

这就是我最终解决这个问题的方法(没有双关语意思):

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

然后我在模板中使用Place.display_address。这允许我在没有修改的情况下将原始用户提交的数据保留在数据库中,当我想要标准化的显示版本时,只需使用display_address

公开征求意见/建议。

答案 3 :(得分:2)

一种选择是使用Geopy查找Yahoo或Google Maps等人的地址,然后返回与之匹配的地址的完整地址。您可能必须注意在返回的地址中截断的公寓号码(例如“221 Amsterdam Av#330”变为“221 AMSTERDAM AVENUE”)。此外,您还将获得用户可能也缩写或拼写错误的城市/州/国家/地区信息。

如果有多个匹配项,您可以提示用户提供有关其地址的反馈。在没有匹配的情况下,您也可以让用户知道,并且可能允许地址保存,具体取决于有效地址的重要程度,以及您对地址查找提供程序的有效性的信任程度。

关于在形式与模型中进行这种规范化,我不知道首选的Django方式是什么,但我的偏好是在形式中,例如:

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

您可以在模型(或一些helpers.py文件)中抛出此查找函数,以防您想在其他区域重用它