Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactor the choices for localflavor's USStateField, and add new US p…

…ostal code support. Fixes #14937 and #9022, refs #10308 and #8425.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15029 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 5ed6e7a4d50eb5a2193133c67fd6fe8f6bbd0e5d 1 parent f117b91
@ubernostrum ubernostrum authored
View
9 django/contrib/localflavor/us/forms.py
@@ -111,3 +111,12 @@ class USStateSelect(Select):
def __init__(self, attrs=None):
from us_states import STATE_CHOICES
super(USStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
+
+class USPSSelect(Select):
+ """
+ A Select widget that uses a list of US Postal Service codes as its
+ choices.
+ """
+ def __init__(self, attrs=None):
+ from us_states import USPS_CHOICES
+ super(USPSSelect, self).__init__(attrs, choices=USPS_CHOICES)
View
10 django/contrib/localflavor/us/models.py
@@ -2,6 +2,7 @@
from django.utils.translation import ugettext_lazy as _
from django.db.models.fields import CharField
from django.contrib.localflavor.us.us_states import STATE_CHOICES
+from django.contrib.localflavor.us.us_states import USPS_CHOICES
class USStateField(CharField):
@@ -12,6 +13,15 @@ def __init__(self, *args, **kwargs):
kwargs['max_length'] = 2
super(USStateField, self).__init__(*args, **kwargs)
+class USPostalCodeField(CharField):
+
+ description = _("U.S. postal code (two uppercase letters)")
+
+ def __init__(self, *args, **kwargs):
+ kwargs['choices'] = USPS_CHOICES
+ kwargs['max_length'] = 2
+ super(USPostalCodeField, self).__init__(*args, **kwargs)
+
class PhoneNumberField(CharField):
description = _("Phone number")
View
108 django/contrib/localflavor/us/us_states.py
@@ -1,15 +1,70 @@
"""
-A mapping of state misspellings/abbreviations to normalized abbreviations, and
-an alphabetical list of states for use as `choices` in a formfield.
+A mapping of state misspellings/abbreviations to normalized
+abbreviations, and alphabetical lists of US states, territories,
+military mail regions and non-US states to which the US provides
+postal service.
This exists in this standalone file so that it's only imported into memory
when explicitly needed.
"""
-STATE_CHOICES = (
+# The 48 contiguous states, plus the District of Columbia.
+CONTIGUOUS_STATES = (
+ ('AL', 'Alabama'),
+ ('AZ', 'Arizona'),
+ ('AR', 'Arkansas'),
+ ('CA', 'California'),
+ ('CO', 'Colorado'),
+ ('CT', 'Connecticut'),
+ ('DE', 'Delaware'),
+ ('DC', 'District of Columbia'),
+ ('FL', 'Florida'),
+ ('GA', 'Georgia'),
+ ('ID', 'Idaho'),
+ ('IL', 'Illinois'),
+ ('IN', 'Indiana'),
+ ('IA', 'Iowa'),
+ ('KS', 'Kansas'),
+ ('KY', 'Kentucky'),
+ ('LA', 'Louisiana'),
+ ('ME', 'Maine'),
+ ('MD', 'Maryland'),
+ ('MA', 'Massachusetts'),
+ ('MI', 'Michigan'),
+ ('MN', 'Minnesota'),
+ ('MS', 'Mississippi'),
+ ('MO', 'Missouri'),
+ ('MT', 'Montana'),
+ ('NE', 'Nebraska'),
+ ('NV', 'Nevada'),
+ ('NH', 'New Hampshire'),
+ ('NJ', 'New Jersey'),
+ ('NM', 'New Mexico'),
+ ('NY', 'New York'),
+ ('NC', 'North Carolina'),
+ ('ND', 'North Dakota'),
+ ('OH', 'Ohio'),
+ ('OK', 'Oklahoma'),
+ ('OR', 'Oregon'),
+ ('PA', 'Pennsylvania'),
+ ('RI', 'Rhode Island'),
+ ('SC', 'South Carolina'),
+ ('SD', 'South Dakota'),
+ ('TN', 'Tennessee'),
+ ('TX', 'Texas'),
+ ('UT', 'Utah'),
+ ('VT', 'Vermont'),
+ ('VA', 'Virginia'),
+ ('WA', 'Washington'),
+ ('WV', 'West Virginia'),
+ ('WI', 'Wisconsin'),
+ ('WY', 'Wyoming'),
+)
+
+# All 50 states, plus the District of Columbia.
+US_STATES = (
('AL', 'Alabama'),
('AK', 'Alaska'),
- ('AS', 'American Samoa'),
('AZ', 'Arizona'),
('AR', 'Arkansas'),
('CA', 'California'),
@@ -19,7 +74,6 @@
('DC', 'District of Columbia'),
('FL', 'Florida'),
('GA', 'Georgia'),
- ('GU', 'Guam'),
('HI', 'Hawaii'),
('ID', 'Idaho'),
('IL', 'Illinois'),
@@ -44,12 +98,10 @@
('NY', 'New York'),
('NC', 'North Carolina'),
('ND', 'North Dakota'),
- ('MP', 'Northern Mariana Islands'),
('OH', 'Ohio'),
('OK', 'Oklahoma'),
('OR', 'Oregon'),
('PA', 'Pennsylvania'),
- ('PR', 'Puerto Rico'),
('RI', 'Rhode Island'),
('SC', 'South Carolina'),
('SD', 'South Dakota'),
@@ -57,7 +109,6 @@
('TX', 'Texas'),
('UT', 'Utah'),
('VT', 'Vermont'),
- ('VI', 'Virgin Islands'),
('VA', 'Virginia'),
('WA', 'Washington'),
('WV', 'West Virginia'),
@@ -65,6 +116,47 @@
('WY', 'Wyoming'),
)
+# Non-state territories.
+US_TERRITORIES = (
+ ('AS', 'American Samoa'),
+ ('GU', 'Guam'),
+ ('MP', 'Northern Mariana Islands'),
+ ('PR', 'Puerto Rico'),
+ ('VI', 'Virgin Islands'),
+)
+
+# Military postal "states". Note that 'AE' actually encompasses
+# Europe, Canada, Africa and the Middle East.
+ARMED_FORCES_STATES = (
+ ('AA', 'Armed Forces Americas'),
+ ('AE', 'Armed Forces Europe'),
+ ('AP', 'Armed Forces Pacific'),
+)
+
+# Non-US locations serviced by USPS (under Compact of Free
+# Association).
+COFA_STATES = (
+ ('FM', 'Federated States of Micronesia'),
+ ('MH', 'Marshall Islands'),
+ ('PW', 'Palau'),
+)
+
+# Obsolete abbreviations (no longer US territories/USPS service, or
+# code changed).
+OBSOLETE_STATES = (
+ ('CM', 'Commonwealth of the Northern Mariana Islands'), # Is now 'MP'
+ ('CZ', 'Panama Canal Zone'), # Reverted to Panama 1979
+ ('PI', 'Philippine Islands'), # Philippine independence 1946
+ ('TT', 'Trust Territory of the Pacific Islands'), # Became the independent COFA states + Northern Mariana Islands 1979-1994
+)
+
+
+# All US states and territories plus DC and military mail.
+STATE_CHOICES = US_STATES + US_TERRITORIES + ARMED_FORCES_STATES
+
+# All US Postal Service locations.
+USPS_CHOICES = US_STATES + US_TERRITORIES + ARMED_FORCES_STATES + COFA_STATES
+
STATES_NORMALIZED = {
'ak': 'AK',
'al': 'AL',
View
65 docs/ref/contrib/localflavor.txt
@@ -937,6 +937,11 @@ United States of America (``us``)
A form ``Select`` widget that uses a list of U.S. states/territories as its
choices.
+.. class:: us.forms.USPSSelect
+
+ A form ``Select`` widget that uses a list of U.S Postal Service
+ state, territory and country abbreviations as its choices.
+
.. class:: us.models.PhoneNumberField
A :class:`CharField` that checks that the value is a valid U.S.A.-style phone
@@ -947,6 +952,66 @@ United States of America (``us``)
A model field that forms represent as a ``forms.USStateField`` field and
stores the two-letter U.S. state abbreviation in the database.
+.. class:: us.models.USPostalCodeField
+
+ A model field that forms represent as a ``forms.USPSSelect`` field
+ and stores the two-letter U.S Postal Service abbreviation in the
+ database.
+
+Additionally, a variety of choice tuples are provided in
+``django.contrib.localflavor.us.us_states``, allowing customized model
+and form fields, and form presentations, for subsets of U.S states,
+territories and U.S Postal Service abbreviations:
+
+.. data:: us.us_states.CONTIGUOUS_STATES
+
+ A tuple of choices of the postal abbreviations for the
+ contiguous or "lower 48" states (i.e., all except Alaska and
+ Hawaii), plus the District of Columbia.
+
+.. data:: us.us_states.US_STATES
+
+ A tuple of choices of the postal abbreviations for all
+ 50 U.S. states, plus the District of Columbia.
+
+.. data:: us.us_states.US_TERRITORIES
+
+ A tuple of choices of the postal abbreviations for U.S
+ territories: American Samoa, Guam, the Northern Mariana Islands,
+ Puerto Rico and the U.S. Virgin Islands.
+
+.. data:: us.us_states.ARMED_FORCES_STATES
+
+ A tuple of choices of the postal abbreviations of the three U.S
+ military postal "states": Armed Forces Americas, Armed Forces
+ Europe and Armed Forces Pacific.
+
+.. data:: us.us_states.COFA_STATES
+
+ A tuple of choices of the postal abbreviations of the three
+ independent nations which, under the Compact of Free Association,
+ are served by the U.S. Postal Service: the Federated States of
+ Micronesia, the Marshall Islands and Palau.
+
+.. data:: us.us_states.OBSOLETE_STATES
+
+ A tuple of choices of obsolete U.S Postal Service state
+ abbreviations: the former abbreviation for the Northern Mariana
+ Islands, plus the Panama Canal Zone, the Philippines and the
+ former Pacific trust territories.
+
+.. data:: us.us_states.STATE_CHOICES
+
+ A tuple of choices of all postal abbreviations corresponding to U.S states or
+ territories, and the District of Columbia..
+
+.. data:: us.us_states.USPS_CHOICES
+
+ A tuple of choices of all postal abbreviations recognized by the
+ U.S Postal Service (including all states and territories, the
+ District of Columbia, armed forces "states" and independent
+ nations serviced by USPS).
+
Uruguay (``uy``)
================
View
46 docs/releases/1.3-beta-1.txt
@@ -120,6 +120,52 @@ attribute.
.. _r12634: http://code.djangoproject.com/changeset/12634
+Changes to ``USStateField``
+===========================
+
+The :mod:`django.contrib.localflavor` application contains collections
+of code relevant to specific countries or cultures. One such is
+:class:`~django.contrib.localflavor.us.models.USStateField`, which
+provides a field for storing the two-letter postal abbreviation of a
+U.S. state. This field has consistently caused problems, however,
+because it is often used to store the state portion of a U.S postal
+address, but not all "states" recognized by the U.S Postal Service are
+actually states of the U.S. or even U.S. territory. Several
+compromises over the list of choices resulted in some users feeling
+the field supported too many locations, while others felt it supported
+too few.
+
+In Django 1.3 we're taking a new approach to this problem, implemented
+as a pair of changes:
+
+* The choice list for `USStateField` has changed. Previously, it
+ consisted of the 50 U.S. states, the District of Columbia and
+ U.S. overseas territories. As of Django 1.3 it includes all previous
+ choices, plus the U.S. Armed Forces postal codes.
+
+* A new model field,
+ :class:`django.contrib.localflavor.us.models.USPostalCodeField`, has
+ been added which draws its choices from a list of all postal
+ abbreviations recognized by the U.S Postal Service. This includes
+ all abbreviations recognized by `USStateField`, plus three
+ independent nations -- the Federated States of Micronesia, the
+ Republic of the Marshall Islands and the Republic of Palau -- which
+ are serviced under treaty by the U.S. postal system. A new form
+ widget, :class:`django.contrib.localflavor.us.forms.USPSSelect`, is
+ also available and provides the same set of choices.
+
+Additionally, several finer-grained choice tuples are provided which
+allow mixing and matching of subsets of the U.S. states and
+territories, and other locations serviced by the U.S. postal
+system. Consult the :mod:`django.contrib.localflavor` documentation
+for more details.
+
+The change to `USStateField` is technically backwards-incompatible for
+users who expect this field to exclude Armed Forces locations. If you
+need to support U.S. mailing addresses without Armed Forces locations,
+see the list of choice tuples available in the localflavor
+documentation.
+
The Django 1.3 roadmap
======================
View
2  tests/regressiontests/localflavor/us/models.py
@@ -1,5 +1,6 @@
from django.db import models
from django.contrib.localflavor.us.models import USStateField
+from django.contrib.localflavor.us.models import USPostalCodeField
# When creating models you need to remember to add a app_label as
# 'localflavor', so your model can be found
@@ -8,6 +9,7 @@ class USPlace(models.Model):
state = USStateField(blank=True)
state_req = USStateField()
state_default = USStateField(default="CA", blank=True)
+ postal_code = USPostalCodeField(blank=True)
name = models.CharField(max_length=20)
class Meta:
app_label = 'localflavor'
View
85 tests/regressiontests/localflavor/us/tests.py
@@ -3,7 +3,7 @@
class USLocalflavorTests(TestCase):
def setUp(self):
- self.form = USPlaceForm({'state':'GA', 'state_req':'NC', 'name':'impossible'})
+ self.form = USPlaceForm({'state':'GA', 'state_req':'NC', 'postal_code': 'GA', 'name':'impossible'})
def test_get_display_methods(self):
"""Test that the get_*_display() methods are added to the model instances."""
@@ -24,7 +24,6 @@ def test_field_blank_option(self):
<option value="">---------</option>
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
-<option value="AS">American Samoa</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<option value="CA">California</option>
@@ -34,7 +33,6 @@ def test_field_blank_option(self):
<option value="DC">District of Columbia</option>
<option value="FL">Florida</option>
<option value="GA" selected="selected">Georgia</option>
-<option value="GU">Guam</option>
<option value="HI">Hawaii</option>
<option value="ID">Idaho</option>
<option value="IL">Illinois</option>
@@ -59,12 +57,10 @@ def test_field_blank_option(self):
<option value="NY">New York</option>
<option value="NC">North Carolina</option>
<option value="ND">North Dakota</option>
-<option value="MP">Northern Mariana Islands</option>
<option value="OH">Ohio</option>
<option value="OK">Oklahoma</option>
<option value="OR">Oregon</option>
<option value="PA">Pennsylvania</option>
-<option value="PR">Puerto Rico</option>
<option value="RI">Rhode Island</option>
<option value="SC">South Carolina</option>
<option value="SD">South Dakota</option>
@@ -72,11 +68,88 @@ def test_field_blank_option(self):
<option value="TX">Texas</option>
<option value="UT">Utah</option>
<option value="VT">Vermont</option>
-<option value="VI">Virgin Islands</option>
<option value="VA">Virginia</option>
<option value="WA">Washington</option>
<option value="WV">West Virginia</option>
<option value="WI">Wisconsin</option>
<option value="WY">Wyoming</option>
+<option value="AS">American Samoa</option>
+<option value="GU">Guam</option>
+<option value="MP">Northern Mariana Islands</option>
+<option value="PR">Puerto Rico</option>
+<option value="VI">Virgin Islands</option>
+<option value="AA">Armed Forces Americas</option>
+<option value="AE">Armed Forces Europe</option>
+<option value="AP">Armed Forces Pacific</option>
</select>"""
self.assertEqual(str(self.form['state']), state_select_html)
+
+ def test_full_postal_code_list(self):
+ """Test that the full USPS code field is really the full list."""
+ usps_select_html = """\
+<select name="postal_code" id="id_postal_code">
+<option value="">---------</option>
+<option value="AL">Alabama</option>
+<option value="AK">Alaska</option>
+<option value="AZ">Arizona</option>
+<option value="AR">Arkansas</option>
+<option value="CA">California</option>
+<option value="CO">Colorado</option>
+<option value="CT">Connecticut</option>
+<option value="DE">Delaware</option>
+<option value="DC">District of Columbia</option>
+<option value="FL">Florida</option>
+<option value="GA" selected="selected">Georgia</option>
+<option value="HI">Hawaii</option>
+<option value="ID">Idaho</option>
+<option value="IL">Illinois</option>
+<option value="IN">Indiana</option>
+<option value="IA">Iowa</option>
+<option value="KS">Kansas</option>
+<option value="KY">Kentucky</option>
+<option value="LA">Louisiana</option>
+<option value="ME">Maine</option>
+<option value="MD">Maryland</option>
+<option value="MA">Massachusetts</option>
+<option value="MI">Michigan</option>
+<option value="MN">Minnesota</option>
+<option value="MS">Mississippi</option>
+<option value="MO">Missouri</option>
+<option value="MT">Montana</option>
+<option value="NE">Nebraska</option>
+<option value="NV">Nevada</option>
+<option value="NH">New Hampshire</option>
+<option value="NJ">New Jersey</option>
+<option value="NM">New Mexico</option>
+<option value="NY">New York</option>
+<option value="NC">North Carolina</option>
+<option value="ND">North Dakota</option>
+<option value="OH">Ohio</option>
+<option value="OK">Oklahoma</option>
+<option value="OR">Oregon</option>
+<option value="PA">Pennsylvania</option>
+<option value="RI">Rhode Island</option>
+<option value="SC">South Carolina</option>
+<option value="SD">South Dakota</option>
+<option value="TN">Tennessee</option>
+<option value="TX">Texas</option>
+<option value="UT">Utah</option>
+<option value="VT">Vermont</option>
+<option value="VA">Virginia</option>
+<option value="WA">Washington</option>
+<option value="WV">West Virginia</option>
+<option value="WI">Wisconsin</option>
+<option value="WY">Wyoming</option>
+<option value="AS">American Samoa</option>
+<option value="GU">Guam</option>
+<option value="MP">Northern Mariana Islands</option>
+<option value="PR">Puerto Rico</option>
+<option value="VI">Virgin Islands</option>
+<option value="AA">Armed Forces Americas</option>
+<option value="AE">Armed Forces Europe</option>
+<option value="AP">Armed Forces Pacific</option>
+<option value="FM">Federated States of Micronesia</option>
+<option value="MH">Marshall Islands</option>
+<option value="PW">Palau</option>
+</select>"""
+ self.assertEqual(str(self.form['postal_code']), usps_select_html)

0 comments on commit 5ed6e7a

Please sign in to comment.
Something went wrong with that request. Please try again.