Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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)
Please sign in to comment.
Something went wrong with that request. Please try again.