From 349bf5a355ff7ebffb3403a68437e2c524d8b7c7 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Mon, 9 Apr 2007 11:09:17 +0000 Subject: unicode: Merged with trunk up to [4970]. git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@4973 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- AUTHORS | 1 + django/contrib/localflavor/au/__init__.py | 0 django/contrib/localflavor/au/au_states.py | 17 ++ django/contrib/localflavor/au/forms.py | 43 +++++ django/contrib/localflavor/br/br_states.py | 8 +- django/contrib/localflavor/fi/forms.py | 14 +- django/contrib/localflavor/us/__init__.py | 0 django/contrib/localflavor/us/forms.py | 99 ++++++++++++ django/contrib/localflavor/us/us_states.py | 239 ++++++++++++++++++++++++++++ django/contrib/localflavor/usa/__init__.py | 0 django/contrib/localflavor/usa/forms.py | 99 ------------ django/contrib/localflavor/usa/us_states.py | 239 ---------------------------- django/db/models/fields/__init__.py | 2 +- django/newforms/widgets.py | 6 + django/views/debug.py | 3 +- docs/django-admin.txt | 68 ++++---- docs/documentation.txt | 34 ++-- docs/legacy_databases.txt | 6 +- docs/modpython.txt | 9 +- docs/request_response.txt | 4 +- docs/url_dispatch.txt | 56 ++++--- tests/modeltests/model_forms/models.py | 10 +- tests/regressiontests/forms/localflavor.py | 140 +++++++++++++++- tests/regressiontests/forms/tests.py | 26 +-- 24 files changed, 664 insertions(+), 459 deletions(-) create mode 100644 django/contrib/localflavor/au/__init__.py create mode 100644 django/contrib/localflavor/au/au_states.py create mode 100644 django/contrib/localflavor/au/forms.py create mode 100644 django/contrib/localflavor/us/__init__.py create mode 100644 django/contrib/localflavor/us/forms.py create mode 100644 django/contrib/localflavor/us/us_states.py delete mode 100644 django/contrib/localflavor/usa/__init__.py delete mode 100644 django/contrib/localflavor/usa/forms.py delete mode 100644 django/contrib/localflavor/usa/us_states.py diff --git a/AUTHORS b/AUTHORS index cca3247981..119f6378eb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -88,6 +88,7 @@ answer newbie questions, and generally made Django that much better: Dirk Eschler Marc Fargas favo@exoweb.net + Matthew Flanagan Eric Floehr Jorge Gajon gandalf@owca.info diff --git a/django/contrib/localflavor/au/__init__.py b/django/contrib/localflavor/au/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django/contrib/localflavor/au/au_states.py b/django/contrib/localflavor/au/au_states.py new file mode 100644 index 0000000000..578d61bb01 --- /dev/null +++ b/django/contrib/localflavor/au/au_states.py @@ -0,0 +1,17 @@ +""" +An alphabetical list of states for use as `choices` in a formfield. + +This exists in this standalone file so that it's only imported into memory +when explicitly needed. +""" + +STATE_CHOICES = ( + ('ACT', 'Australian Capital Territory'), + ('NSW', 'New South Wales'), + ('NT', 'Northern Territory'), + ('QLD', 'Queensland'), + ('SA', 'South Australia'), + ('TAS', 'Tasmania'), + ('VIC', 'Victoria'), + ('WA', 'Western Australia'), +) diff --git a/django/contrib/localflavor/au/forms.py b/django/contrib/localflavor/au/forms.py new file mode 100644 index 0000000000..b81a903d13 --- /dev/null +++ b/django/contrib/localflavor/au/forms.py @@ -0,0 +1,43 @@ +""" +Australian-specific Form helpers +""" + +from django.newforms import ValidationError +from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES +from django.newforms.util import smart_unicode +from django.utils.translation import gettext +import re + +PHONE_DIGITS_RE = re.compile(r'^(\d{10})$') + +class AUPostCodeField(RegexField): + """Australian post code field.""" + def __init__(self, *args, **kwargs): + super(AUPostCodeField, self).__init__(r'^\d{4}$', + max_length=None, min_length=None, + error_message=gettext(u'Enter a 4 digit post code.'), + *args, **kwargs) + +class AUPhoneNumberField(Field): + """Australian phone number field.""" + def clean(self, value): + """Validate a phone number. Strips parentheses, whitespace and + hyphens. + """ + super(AUPhoneNumberField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + value = re.sub('(\(|\)|\s+|-)', '', smart_unicode(value)) + phone_match = PHONE_DIGITS_RE.search(value) + if phone_match: + return u'%s' % phone_match.group(1) + raise ValidationError(u'Phone numbers must contain 10 digits.') + +class AUStateSelect(Select): + """ + A Select widget that uses a list of Australian states/territories as its + choices. + """ + def __init__(self, attrs=None): + from au_states import STATE_CHOICES # relative import + super(AUStateSelect, self).__init__(attrs, choices=STATE_CHOICES) diff --git a/django/contrib/localflavor/br/br_states.py b/django/contrib/localflavor/br/br_states.py index c6ce0a1bb7..98e54bca2c 100644 --- a/django/contrib/localflavor/br/br_states.py +++ b/django/contrib/localflavor/br/br_states.py @@ -1,11 +1,9 @@ # -*- coding: utf-8 -*- """ -A brazilian mapping of state misspellings/abbreviations to normalized -abbreviations, and an alphabetical list of states for use as `choices -in a formfield. +An alphabetical list of Brazilian states for use as `choices` in a formfield. -This exists in this standalone file so that it's only imported into -memory when explicitly needed. +This exists in this standalone file so that it's only imported into memory +when explicitly needed. """ STATE_CHOICES = ( diff --git a/django/contrib/localflavor/fi/forms.py b/django/contrib/localflavor/fi/forms.py index a2b2eed5c2..da5cb5f2a8 100644 --- a/django/contrib/localflavor/fi/forms.py +++ b/django/contrib/localflavor/fi/forms.py @@ -26,8 +26,8 @@ class FISocialSecurityNumber(Field): def clean(self, value): super(FISocialSecurityNumber, self).clean(value) if value in EMPTY_VALUES: - return u'' - + return u'' + checkmarks = "0123456789ABCDEFHJKLMNPRSTUVWXY" result = re.match(r"""^ (?P([0-2]\d|3[01]) @@ -35,13 +35,11 @@ class FISocialSecurityNumber(Field): (\d{2})) [A+-] (?P(\d{3})) - (?P[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE) + (?P[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE) if not result: raise ValidationError(gettext(u'Enter a valid Finnish social security number.')) - checksum = int(result.groupdict()['date'] + result.groupdict()['serial']) - - if checkmarks[checksum % len(checkmarks)] == result.groupdict()['chechsum'].upper(): + gd = result.groupdict() + checksum = int(gd['date'] + gd['serial']) + if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper(): return u'%s' % value.upper() - raise ValidationError(gettext(u'Enter a valid Finnish social security number.')) - diff --git a/django/contrib/localflavor/us/__init__.py b/django/contrib/localflavor/us/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django/contrib/localflavor/us/forms.py b/django/contrib/localflavor/us/forms.py new file mode 100644 index 0000000000..feda68291b --- /dev/null +++ b/django/contrib/localflavor/us/forms.py @@ -0,0 +1,99 @@ +""" +USA-specific Form helpers +""" + +from django.newforms import ValidationError +from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES +from django.utils.encoding import smart_unicode +from django.utils.translation import gettext +import re + +phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$') +ssn_re = re.compile(r"^(?P\d{3})[-\ ]?(?P\d{2})[-\ ]?(?P\d{4})$") + +class USZipCodeField(RegexField): + def __init__(self, *args, **kwargs): + super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$', + max_length=None, min_length=None, + error_message=gettext(u'Enter a zip code in the format XXXXX or XXXXX-XXXX.'), + *args, **kwargs) + +class USPhoneNumberField(Field): + def clean(self, value): + super(USPhoneNumberField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + value = re.sub('(\(|\)|\s+)', '', smart_unicode(value)) + m = phone_digits_re.search(value) + if m: + return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) + raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.') + +class USSocialSecurityNumberField(Field): + """ + A United States Social Security number. + + Checks the following rules to determine whether the number is valid: + + * Conforms to the XXX-XX-XXXX format. + * No group consists entirely of zeroes. + * The leading group is not "666" (block "666" will never be allocated). + * The number is not in the promotional block 987-65-4320 through 987-65-4329, + which are permanently invalid. + * The number is not one known to be invalid due to otherwise widespread + promotional use or distribution (e.g., the Woolworth's number or the 1962 + promotional number). + """ + def clean(self, value): + super(USSocialSecurityNumberField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + msg = gettext(u'Enter a valid U.S. Social Security number in XXX-XX-XXXX format.') + match = re.match(ssn_re, value) + if not match: + raise ValidationError(msg) + area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial'] + + # First pass: no blocks of all zeroes. + if area == '000' or \ + group == '00' or \ + serial == '0000': + raise ValidationError(msg) + + # Second pass: promotional and otherwise permanently invalid numbers. + if area == '666' or \ + (area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \ + value == '078-05-1120' or \ + value == '219-09-9999': + raise ValidationError(msg) + return u'%s-%s-%s' % (area, group, serial) + +class USStateField(Field): + """ + A form field that validates its input is a U.S. state name or abbreviation. + It normalizes the input to the standard two-leter postal service + abbreviation for the given state. + """ + def clean(self, value): + from us_states import STATES_NORMALIZED # relative import + super(USStateField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + try: + value = value.strip().lower() + except AttributeError: + pass + else: + try: + return STATES_NORMALIZED[value.strip().lower()].decode('ascii') + except KeyError: + pass + raise ValidationError(u'Enter a U.S. state or territory.') + +class USStateSelect(Select): + """ + A Select widget that uses a list of U.S. states/territories as its choices. + """ + def __init__(self, attrs=None): + from us_states import STATE_CHOICES # relative import + super(USStateSelect, self).__init__(attrs, choices=STATE_CHOICES) diff --git a/django/contrib/localflavor/us/us_states.py b/django/contrib/localflavor/us/us_states.py new file mode 100644 index 0000000000..89124a4b69 --- /dev/null +++ b/django/contrib/localflavor/us/us_states.py @@ -0,0 +1,239 @@ +""" +A mapping of state misspellings/abbreviations to normalized abbreviations, and +an alphabetical list of states for use as `choices` in a formfield. + +This exists in this standalone file so that it's only imported into memory +when explicitly needed. +""" + +STATE_CHOICES = ( + ('AL', 'Alabama'), + ('AK', 'Alaska'), + ('AS', 'American Samoa'), + ('AZ', 'Arizona'), + ('AR', 'Arkansas'), + ('CA', 'California'), + ('CO', 'Colorado'), + ('CT', 'Connecticut'), + ('DE', 'Deleware'), + ('DC', 'District of Columbia'), + ('FM', 'Federated States of Micronesia'), + ('FL', 'Florida'), + ('GA', 'Georgia'), + ('GU', 'Guam'), + ('HI', 'Hawaii'), + ('ID', 'Idaho'), + ('IL', 'Illinois'), + ('IN', 'Indiana'), + ('IA', 'Iowa'), + ('KS', 'Kansas'), + ('KY', 'Kentucky'), + ('LA', 'Louisiana'), + ('ME', 'Maine'), + ('MH', 'Marshall Islands'), + ('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'), + ('MP', 'Northern Mariana Islands'), + ('OH', 'Ohio'), + ('OK', 'Oklahoma'), + ('OR', 'Oregon'), + ('PW', 'Palau'), + ('PA', 'Pennsylvania'), + ('PR', 'Puerto Rico'), + ('RI', 'Rhode Island'), + ('SC', 'South Carolina'), + ('SD', 'South Dakota'), + ('TN', 'Tennessee'), + ('TX', 'Texas'), + ('UT', 'Utah'), + ('VT', 'Vermont'), + ('VI', 'Virgin Islands'), + ('VA', 'Virginia'), + ('WA', 'Washington'), + ('WV', 'West Virginia'), + ('WI', 'Wisconsin'), + ('WY', 'Wyoming'), +) + +STATES_NORMALIZED = { + 'ak': 'AK', + 'al': 'AL', + 'ala': 'AL', + 'alabama': 'AL', + 'alaska': 'AK', + 'american samao': 'AS', + 'american samoa': 'AS', + 'ar': 'AR', + 'ariz': 'AZ', + 'arizona': 'AZ', + 'ark': 'AR', + 'arkansas': 'AR', + 'as': 'AS', + 'az': 'AZ', + 'ca': 'CA', + 'calf': 'CA', + 'calif': 'CA', + 'california': 'CA', + 'co': 'CO', + 'colo': 'CO', + 'colorado': 'CO', + 'conn': 'CT', + 'connecticut': 'CT', + 'ct': 'CT', + 'dc': 'DC', + 'de': 'DE', + 'del': 'DE', + 'delaware': 'DE', + 'district of columbia': 'DC', + 'federated states of micronesia': 'FM', + 'fl': 'FL', + 'fla': 'FL', + 'florida': 'FL', + 'fm': 'FM', + 'ga': 'GA', + 'georgia': 'GA', + 'gu': 'GU', + 'guam': 'GU', + 'hawaii': 'HI', + 'hi': 'HI', + 'ia': 'IA', + 'id': 'ID', + 'idaho': 'ID', + 'il': 'IL', + 'ill': 'IL', + 'illinois': 'IL', + 'in': 'IN', + 'ind': 'IN', + 'indiana': 'IN', + 'iowa': 'IA', + 'kan': 'KS', + 'kans': 'KS', + 'kansas': 'KS', + 'kentucky': 'KY', + 'ks': 'KS', + 'ky': 'KY', + 'la': 'LA', + 'louisiana': 'LA', + 'ma': 'MA', + 'maine': 'ME', + 'marianas islands': 'MP', + 'marianas islands of the pacific': 'MP', + 'marinas islands of the pacific': 'MP', + 'maryland': 'MD', + 'mass': 'MA', + 'massachusetts': 'MA', + 'massachussetts': 'MA', + 'md': 'MD', + 'me': 'ME', + 'mi': 'MI', + 'mich': 'MI', + 'michigan': 'MI', + 'micronesia': 'FM', + 'minn': 'MN', + 'minnesota': 'MN', + 'miss': 'MS', + 'mississippi': 'MS', + 'missouri': 'MO', + 'mn': 'MN', + 'mo': 'MO', + 'mont': 'MT', + 'montana': 'MT', + 'mp': 'MP', + 'ms': 'MS', + 'mt': 'MT', + 'n d': 'ND', + 'n dak': 'ND', + 'n h': 'NH', + 'n j': 'NJ', + 'n m': 'NM', + 'n mex': 'NM', + 'nc': 'NC', + 'nd': 'ND', + 'ne': 'NE', + 'neb': 'NE', + 'nebr': 'NE', + 'nebraska': 'NE', + 'nev': 'NV', + 'nevada': 'NV', + 'new hampshire': 'NH', + 'new jersey': 'NJ', + 'new mexico': 'NM', + 'new york': 'NY', + 'nh': 'NH', + 'nj': 'NJ', + 'nm': 'NM', + 'nmex': 'NM', + 'north carolina': 'NC', + 'north dakota': 'ND', + 'northern mariana islands': 'MP', + 'nv': 'NV', + 'ny': 'NY', + 'oh': 'OH', + 'ohio': 'OH', + 'ok': 'OK', + 'okla': 'OK', + 'oklahoma': 'OK', + 'or': 'OR', + 'ore': 'OR', + 'oreg': 'OR', + 'oregon': 'OR', + 'pa': 'PA', + 'penn': 'PA', + 'pennsylvania': 'PA', + 'pr': 'PR', + 'puerto rico': 'PR', + 'rhode island': 'RI', + 'ri': 'RI', + 's dak': 'SD', + 'sc': 'SC', + 'sd': 'SD', + 'sdak': 'SD', + 'south carolina': 'SC', + 'south dakota': 'SD', + 'tenn': 'TN', + 'tennessee': 'TN', + 'territory of hawaii': 'HI', + 'tex': 'TX', + 'texas': 'TX', + 'tn': 'TN', + 'tx': 'TX', + 'us virgin islands': 'VI', + 'usvi': 'VI', + 'ut': 'UT', + 'utah': 'UT', + 'va': 'VA', + 'vermont': 'VT', + 'vi': 'VI', + 'viginia': 'VA', + 'virgin islands': 'VI', + 'virgina': 'VA', + 'virginia': 'VA', + 'vt': 'VT', + 'w va': 'WV', + 'wa': 'WA', + 'wash': 'WA', + 'washington': 'WA', + 'west virginia': 'WV', + 'wi': 'WI', + 'wis': 'WI', + 'wisc': 'WI', + 'wisconsin': 'WI', + 'wv': 'WV', + 'wva': 'WV', + 'wy': 'WY', + 'wyo': 'WY', + 'wyoming': 'WY', +} diff --git a/django/contrib/localflavor/usa/__init__.py b/django/contrib/localflavor/usa/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/django/contrib/localflavor/usa/forms.py b/django/contrib/localflavor/usa/forms.py deleted file mode 100644 index feda68291b..0000000000 --- a/django/contrib/localflavor/usa/forms.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -USA-specific Form helpers -""" - -from django.newforms import ValidationError -from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES -from django.utils.encoding import smart_unicode -from django.utils.translation import gettext -import re - -phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$') -ssn_re = re.compile(r"^(?P\d{3})[-\ ]?(?P\d{2})[-\ ]?(?P\d{4})$") - -class USZipCodeField(RegexField): - def __init__(self, *args, **kwargs): - super(USZipCodeField, self).__init__(r'^\d{5}(?:-\d{4})?$', - max_length=None, min_length=None, - error_message=gettext(u'Enter a zip code in the format XXXXX or XXXXX-XXXX.'), - *args, **kwargs) - -class USPhoneNumberField(Field): - def clean(self, value): - super(USPhoneNumberField, self).clean(value) - if value in EMPTY_VALUES: - return u'' - value = re.sub('(\(|\)|\s+)', '', smart_unicode(value)) - m = phone_digits_re.search(value) - if m: - return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) - raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.') - -class USSocialSecurityNumberField(Field): - """ - A United States Social Security number. - - Checks the following rules to determine whether the number is valid: - - * Conforms to the XXX-XX-XXXX format. - * No group consists entirely of zeroes. - * The leading group is not "666" (block "666" will never be allocated). - * The number is not in the promotional block 987-65-4320 through 987-65-4329, - which are permanently invalid. - * The number is not one known to be invalid due to otherwise widespread - promotional use or distribution (e.g., the Woolworth's number or the 1962 - promotional number). - """ - def clean(self, value): - super(USSocialSecurityNumberField, self).clean(value) - if value in EMPTY_VALUES: - return u'' - msg = gettext(u'Enter a valid U.S. Social Security number in XXX-XX-XXXX format.') - match = re.match(ssn_re, value) - if not match: - raise ValidationError(msg) - area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial'] - - # First pass: no blocks of all zeroes. - if area == '000' or \ - group == '00' or \ - serial == '0000': - raise ValidationError(msg) - - # Second pass: promotional and otherwise permanently invalid numbers. - if area == '666' or \ - (area == '987' and group == '65' and 4320 <= int(serial) <= 4329) or \ - value == '078-05-1120' or \ - value == '219-09-9999': - raise ValidationError(msg) - return u'%s-%s-%s' % (area, group, serial) - -class USStateField(Field): - """ - A form field that validates its input is a U.S. state name or abbreviation. - It normalizes the input to the standard two-leter postal service - abbreviation for the given state. - """ - def clean(self, value): - from us_states import STATES_NORMALIZED # relative import - super(USStateField, self).clean(value) - if value in EMPTY_VALUES: - return u'' - try: - value = value.strip().lower() - except AttributeError: - pass - else: - try: - return STATES_NORMALIZED[value.strip().lower()].decode('ascii') - except KeyError: - pass - raise ValidationError(u'Enter a U.S. state or territory.') - -class USStateSelect(Select): - """ - A Select widget that uses a list of U.S. states/territories as its choices. - """ - def __init__(self, attrs=None): - from us_states import STATE_CHOICES # relative import - super(USStateSelect, self).__init__(attrs, choices=STATE_CHOICES) diff --git a/django/contrib/localflavor/usa/us_states.py b/django/contrib/localflavor/usa/us_states.py deleted file mode 100644 index 89124a4b69..0000000000 --- a/django/contrib/localflavor/usa/us_states.py +++ /dev/null @@ -1,239 +0,0 @@ -""" -A mapping of state misspellings/abbreviations to normalized abbreviations, and -an alphabetical list of states for use as `choices` in a formfield. - -This exists in this standalone file so that it's only imported into memory -when explicitly needed. -""" - -STATE_CHOICES = ( - ('AL', 'Alabama'), - ('AK', 'Alaska'), - ('AS', 'American Samoa'), - ('AZ', 'Arizona'), - ('AR', 'Arkansas'), - ('CA', 'California'), - ('CO', 'Colorado'), - ('CT', 'Connecticut'), - ('DE', 'Deleware'), - ('DC', 'District of Columbia'), - ('FM', 'Federated States of Micronesia'), - ('FL', 'Florida'), - ('GA', 'Georgia'), - ('GU', 'Guam'), - ('HI', 'Hawaii'), - ('ID', 'Idaho'), - ('IL', 'Illinois'), - ('IN', 'Indiana'), - ('IA', 'Iowa'), - ('KS', 'Kansas'), - ('KY', 'Kentucky'), - ('LA', 'Louisiana'), - ('ME', 'Maine'), - ('MH', 'Marshall Islands'), - ('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'), - ('MP', 'Northern Mariana Islands'), - ('OH', 'Ohio'), - ('OK', 'Oklahoma'), - ('OR', 'Oregon'), - ('PW', 'Palau'), - ('PA', 'Pennsylvania'), - ('PR', 'Puerto Rico'), - ('RI', 'Rhode Island'), - ('SC', 'South Carolina'), - ('SD', 'South Dakota'), - ('TN', 'Tennessee'), - ('TX', 'Texas'), - ('UT', 'Utah'), - ('VT', 'Vermont'), - ('VI', 'Virgin Islands'), - ('VA', 'Virginia'), - ('WA', 'Washington'), - ('WV', 'West Virginia'), - ('WI', 'Wisconsin'), - ('WY', 'Wyoming'), -) - -STATES_NORMALIZED = { - 'ak': 'AK', - 'al': 'AL', - 'ala': 'AL', - 'alabama': 'AL', - 'alaska': 'AK', - 'american samao': 'AS', - 'american samoa': 'AS', - 'ar': 'AR', - 'ariz': 'AZ', - 'arizona': 'AZ', - 'ark': 'AR', - 'arkansas': 'AR', - 'as': 'AS', - 'az': 'AZ', - 'ca': 'CA', - 'calf': 'CA', - 'calif': 'CA', - 'california': 'CA', - 'co': 'CO', - 'colo': 'CO', - 'colorado': 'CO', - 'conn': 'CT', - 'connecticut': 'CT', - 'ct': 'CT', - 'dc': 'DC', - 'de': 'DE', - 'del': 'DE', - 'delaware': 'DE', - 'district of columbia': 'DC', - 'federated states of micronesia': 'FM', - 'fl': 'FL', - 'fla': 'FL', - 'florida': 'FL', - 'fm': 'FM', - 'ga': 'GA', - 'georgia': 'GA', - 'gu': 'GU', - 'guam': 'GU', - 'hawaii': 'HI', - 'hi': 'HI', - 'ia': 'IA', - 'id': 'ID', - 'idaho': 'ID', - 'il': 'IL', - 'ill': 'IL', - 'illinois': 'IL', - 'in': 'IN', - 'ind': 'IN', - 'indiana': 'IN', - 'iowa': 'IA', - 'kan': 'KS', - 'kans': 'KS', - 'kansas': 'KS', - 'kentucky': 'KY', - 'ks': 'KS', - 'ky': 'KY', - 'la': 'LA', - 'louisiana': 'LA', - 'ma': 'MA', - 'maine': 'ME', - 'marianas islands': 'MP', - 'marianas islands of the pacific': 'MP', - 'marinas islands of the pacific': 'MP', - 'maryland': 'MD', - 'mass': 'MA', - 'massachusetts': 'MA', - 'massachussetts': 'MA', - 'md': 'MD', - 'me': 'ME', - 'mi': 'MI', - 'mich': 'MI', - 'michigan': 'MI', - 'micronesia': 'FM', - 'minn': 'MN', - 'minnesota': 'MN', - 'miss': 'MS', - 'mississippi': 'MS', - 'missouri': 'MO', - 'mn': 'MN', - 'mo': 'MO', - 'mont': 'MT', - 'montana': 'MT', - 'mp': 'MP', - 'ms': 'MS', - 'mt': 'MT', - 'n d': 'ND', - 'n dak': 'ND', - 'n h': 'NH', - 'n j': 'NJ', - 'n m': 'NM', - 'n mex': 'NM', - 'nc': 'NC', - 'nd': 'ND', - 'ne': 'NE', - 'neb': 'NE', - 'nebr': 'NE', - 'nebraska': 'NE', - 'nev': 'NV', - 'nevada': 'NV', - 'new hampshire': 'NH', - 'new jersey': 'NJ', - 'new mexico': 'NM', - 'new york': 'NY', - 'nh': 'NH', - 'nj': 'NJ', - 'nm': 'NM', - 'nmex': 'NM', - 'north carolina': 'NC', - 'north dakota': 'ND', - 'northern mariana islands': 'MP', - 'nv': 'NV', - 'ny': 'NY', - 'oh': 'OH', - 'ohio': 'OH', - 'ok': 'OK', - 'okla': 'OK', - 'oklahoma': 'OK', - 'or': 'OR', - 'ore': 'OR', - 'oreg': 'OR', - 'oregon': 'OR', - 'pa': 'PA', - 'penn': 'PA', - 'pennsylvania': 'PA', - 'pr': 'PR', - 'puerto rico': 'PR', - 'rhode island': 'RI', - 'ri': 'RI', - 's dak': 'SD', - 'sc': 'SC', - 'sd': 'SD', - 'sdak': 'SD', - 'south carolina': 'SC', - 'south dakota': 'SD', - 'tenn': 'TN', - 'tennessee': 'TN', - 'territory of hawaii': 'HI', - 'tex': 'TX', - 'texas': 'TX', - 'tn': 'TN', - 'tx': 'TX', - 'us virgin islands': 'VI', - 'usvi': 'VI', - 'ut': 'UT', - 'utah': 'UT', - 'va': 'VA', - 'vermont': 'VT', - 'vi': 'VI', - 'viginia': 'VA', - 'virgin islands': 'VI', - 'virgina': 'VA', - 'virginia': 'VA', - 'vt': 'VT', - 'w va': 'WV', - 'wa': 'WA', - 'wash': 'WA', - 'washington': 'WA', - 'west virginia': 'WV', - 'wi': 'WI', - 'wis': 'WI', - 'wisc': 'WI', - 'wisconsin': 'WI', - 'wv': 'WV', - 'wva': 'WV', - 'wy': 'WY', - 'wyo': 'WY', - 'wyoming': 'WY', -} diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 3972de7d4a..466897ad86 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -761,7 +761,7 @@ class PhoneNumberField(IntegerField): validators.isValidPhone(field_data, all_data) def formfield(self, **kwargs): - from django.contrib.localflavor.usa.forms import USPhoneNumberField + from django.contrib.localflavor.us.forms import USPhoneNumberField defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} defaults.update(kwargs) return USPhoneNumberField(**defaults) diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py index 8d292673a5..f701faa35d 100644 --- a/django/newforms/widgets.py +++ b/django/newforms/widgets.py @@ -121,6 +121,12 @@ class FileInput(Input): input_type = 'file' class Textarea(Widget): + def __init__(self, attrs=None): + # The 'rows' and 'cols' attributes are required for HTML correctness. + self.attrs = {'cols': '40', 'rows': '10'} + if attrs: + self.attrs.update(attrs) + def render(self, name, value, attrs=None): if value is None: value = '' value = smart_unicode(value) diff --git a/django/views/debug.py b/django/views/debug.py index 77b6c2fac2..b49a98a864 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -144,6 +144,7 @@ def technical_404_response(request, exception): t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') c = Context({ 'root_urlconf': settings.ROOT_URLCONF, + 'request_path': request.path[1:], # Trim leading slash 'urlpatterns': tried, 'reason': str(exception), 'request': request, @@ -591,7 +592,7 @@ TECHNICAL_404_TEMPLATE = """
  • {{ pattern|escape }}
  • {% endfor %} -

    The current URL, {{ request.path|escape }}, didn't match any of these.

    +

    The current URL, {{ request_path|escape }}, didn't match any of these.

    {% else %}

    {{ reason|escape }}

    {% endif %} diff --git a/docs/django-admin.txt b/docs/django-admin.txt index 388eaf98ac..cc23bfb559 100644 --- a/docs/django-admin.txt +++ b/docs/django-admin.txt @@ -29,6 +29,9 @@ Generally, when working on a single Django project, it's easier to use ``--settings`` command line option, if you need to switch between multiple Django settings files. +The command-line examples throughout this document use ``django-admin.py`` to +be consistent, but any example can use ``manage.py`` just as well. + Usage ===== @@ -100,23 +103,23 @@ if you're ever curious to see the full list of defaults. dumpdata [appname appname ...] ------------------------------ -Output to standard output all data in the database associated with the named +Output to standard output all data in the database associated with the named application(s). By default, the database will be dumped in JSON format. If you want the output -to be in another format, use the ``--format`` option (e.g., ``format=xml``). -You may specify any Django serialization backend (including any user specified +to be in another format, use the ``--format`` option (e.g., ``format=xml``). +You may specify any Django serialization backend (including any user specified serialization backends named in the ``SERIALIZATION_MODULES`` setting). If no application name is provided, all installed applications will be dumped. -The output of ``dumpdata`` can be used as input for ``loaddata``. +The output of ``dumpdata`` can be used as input for ``loaddata``. flush ----- -Return the database to the state it was in immediately after syncdb was -executed. This means that all data will be removed from the database, any +Return the database to the state it was in immediately after syncdb was +executed. This means that all data will be removed from the database, any post-synchronization handlers will be re-executed, and the ``initial_data`` fixture will be re-installed. @@ -178,37 +181,37 @@ Django will search in three locations for fixtures: 3. In the literal path named by the fixture Django will load any and all fixtures it finds in these locations that match -the provided fixture names. +the provided fixture names. -If the named fixture has a file extension, only fixtures of that type +If the named fixture has a file extension, only fixtures of that type will be loaded. For example:: django-admin.py loaddata mydata.json - -would only load JSON fixtures called ``mydata``. The fixture extension -must correspond to the registered name of a serializer (e.g., ``json`` or + +would only load JSON fixtures called ``mydata``. The fixture extension +must correspond to the registered name of a serializer (e.g., ``json`` or ``xml``). -If you omit the extension, Django will search all available fixture types +If you omit the extension, Django will search all available fixture types for a matching fixture. For example:: django-admin.py loaddata mydata - + would look for any fixture of any fixture type called ``mydata``. If a fixture directory contained ``mydata.json``, that fixture would be loaded -as a JSON fixture. However, if two fixtures with the same name but different -fixture type are discovered (for example, if ``mydata.json`` and -``mydata.xml`` were found in the same fixture directory), fixture -installation will be aborted, and any data installed in the call to +as a JSON fixture. However, if two fixtures with the same name but different +fixture type are discovered (for example, if ``mydata.json`` and +``mydata.xml`` were found in the same fixture directory), fixture +installation will be aborted, and any data installed in the call to ``loaddata`` will be removed from the database. -The fixtures that are named can include directory components. These +The fixtures that are named can include directory components. These directories will be included in the search path. For example:: django-admin.py loaddata foo/bar/mydata.json - -would search ``/fixtures/foo/bar/mydata.json`` for each installed -application, ``/foo/bar/mydata.json`` for each directory in + +would search ``/fixtures/foo/bar/mydata.json`` for each installed +application, ``/foo/bar/mydata.json`` for each directory in ``FIXTURE_DIRS``, and the literal path ``foo/bar/mydata.json``. Note that the order in which fixture files are processed is undefined. However, @@ -219,14 +222,14 @@ end of the transaction. .. admonition:: MySQL and Fixtures - Unfortunately, MySQL isn't capable of completely supporting all the + Unfortunately, MySQL isn't capable of completely supporting all the features of Django fixtures. If you use MyISAM tables, MySQL doesn't - support transactions or constraints, so you won't get a rollback if - multiple transaction files are found, or validation of fixture data. - If you use InnoDB tables, you won't be able to have any forward - references in your data files - MySQL doesn't provide a mechanism to - defer checking of row constraints until a transaction is committed. - + support transactions or constraints, so you won't get a rollback if + multiple transaction files are found, or validation of fixture data. + If you use InnoDB tables, you won't be able to have any forward + references in your data files - MySQL doesn't provide a mechanism to + defer checking of row constraints until a transaction is committed. + reset [appname appname ...] --------------------------- Executes the equivalent of ``sqlreset`` for the given appnames. @@ -397,8 +400,8 @@ this command to install the default apps. If you're installing the ``django.contrib.auth`` application, ``syncdb`` will give you the option of creating a superuser immediately. -``syncdb`` will also search for and install any fixture named ``initial_data``. -See the documentation for ``loaddata`` for details on the specification of +``syncdb`` will also search for and install any fixture named ``initial_data``. +See the documentation for ``loaddata`` for details on the specification of fixture data files. test @@ -471,7 +474,7 @@ Example usage:: django-admin.py dumpdata --indent=4 -Specifies the number of spaces that will be used for indentation when +Specifies the number of spaces that will be used for indentation when pretty-printing output. By default, output will *not* be pretty-printed. Pretty-printing will only be enabled if the indent option is provided. @@ -512,7 +515,8 @@ and `2` is verbose output. ------------ Example usage:: - django-admin.py manage.py --adminmedia=/tmp/new-admin-style/ + + django-admin.py --adminmedia=/tmp/new-admin-style/ Tells Django where to find the various CSS and JavaScript files for the admin interface when running the development server. Normally these files are served diff --git a/docs/documentation.txt b/docs/documentation.txt index bacfb176b1..e72dd47ba1 100644 --- a/docs/documentation.txt +++ b/docs/documentation.txt @@ -42,25 +42,25 @@ On the Web The most recent version of the Django documentation lives at http://www.djangoproject.com/documentation/ . These HTML pages are generated -automatically from the text files in source control every 15 minutes. That -means they reflect the "latest and greatest" in Django -- they include the very -latest corrections and additions, and they discuss the latest Django features, +automatically from the text files in source control. That means they reflect +the "latest and greatest" in Django -- they include the very latest +corrections and additions, and they discuss the latest Django features, which may only be available to users of the Django development version. (See "Differences between versions" below.) -A key advantage of the Web-based documentation is the comment section at the -bottom of each document. This is an area for anybody to submit changes, -corrections and suggestions about the given document. The Django developers -frequently monitor the comments there and use them to improve the documentation -for everybody. +We encourage you to help improve the docs by submitting changes, corrections +and suggestions in the `ticket system`_. The Django developers actively monitor +the ticket system and use your feedback to improve the documentation for +everybody. -We encourage you to help improve the docs: it's easy! Note, however, that -comments should explicitly relate to the documentation, rather than asking -broad tech-support questions. If you need help with your particular Django -setup, try the `django-users mailing list`_ instead of posting a comment to the -documentation. +Note, however, that tickets should explicitly relate to the documentation, +rather than asking broad tech-support questions. If you need help with your +particular Django setup, try the `django-users mailing list`_ or the +`#django IRC channel`_ instead. +.. _ticket system: http://code.djangoproject.com/simpleticket?component=Documentation .. _django-users mailing list: http://groups.google.com/group/django-users +.. _#django IRC channel: irc://irc.freenode.net/django In plain text ------------- @@ -134,14 +134,6 @@ We follow this policy: frozen document that says "These docs are frozen for Django version XXX" and links to the current version of that document. - * Once a document is frozen for a Django release, we remove comments from - that page, in favor of having comments on the latest version of that - document. This is for the sake of maintainability and usability, so that - users have one, and only one, place to leave comments on a particular - document. We realize that some people may be stuck on a previous version - of Django, but we believe the usability problems with multiple versions - of a document the outweigh the benefits. - * The `main documentation Web page`_ includes links to documentation for all previous versions. diff --git a/docs/legacy_databases.txt b/docs/legacy_databases.txt index 8230c11f61..3e2753baca 100644 --- a/docs/legacy_databases.txt +++ b/docs/legacy_databases.txt @@ -39,11 +39,11 @@ Auto-generate the models Django comes with a utility that can create models by introspecting an existing database. You can view the output by running this command:: - django-admin.py inspectdb --settings=path.to.settings + python manage.py inspectdb Save this as a file by using standard Unix output redirection:: - django-admin.py inspectdb --settings=path.to.settings > models.py + python manage.py inspectdb > models.py This feature is meant as a shortcut, not as definitive model generation. See the `django-admin.py documentation`_ for more information. @@ -60,7 +60,7 @@ Install the core Django tables Next, run the ``manage.py syncdb`` command to install any extra needed database records such as admin permissions and content types:: - django-admin.py init --settings=path.to.settings + python manage.py syncdb See whether it worked ===================== diff --git a/docs/modpython.txt b/docs/modpython.txt index 31ec1efe49..37909a09fd 100644 --- a/docs/modpython.txt +++ b/docs/modpython.txt @@ -57,17 +57,16 @@ on it, you'll need to tell mod_python:: .. caution:: - Is you are using Windows, remember that the path will contain backslashes. + If you're using Windows, remember that the path will contain backslashes. This string is passed through Python's string parser twice, so you need to escape each backslash **twice**:: PythonPath "['c:\\\\path\\\\to\\\\project'] + sys.path" - or use raw strings:: + Or, use raw strings:: PythonPath "[r'c:\\path\\to\\project'] + sys.path" - You can also add directives such as ``PythonAutoReload Off`` for performance. See the `mod_python documentation`_ for a full list of options. @@ -161,7 +160,7 @@ If, however, you have no option but to serve media files on the same Apache ``VirtualHost`` as Django, here's how you can turn off mod_python for a particular part of the site:: - + SetHandler None @@ -178,7 +177,7 @@ the ``media`` subdirectory and any URL that ends with ``.jpg``, ``.gif`` or SetEnv DJANGO_SETTINGS_MODULE mysite.settings - + SetHandler None diff --git a/docs/request_response.txt b/docs/request_response.txt index 40f06c859f..c0272461ca 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -483,8 +483,8 @@ In order to use the ``Http404`` exception to its fullest, you should create a template that is displayed when a 404 error is raised. This template should be called ``404.html`` and located in the top level of your template tree. -Customing error views ---------------------- +Customizing error views +----------------------- The 404 (page not found) view ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index e6e1cb6cbf..39eed0625b 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -192,10 +192,11 @@ The remaining arguments should be tuples in this format:: url --- -**New in development version** -The ``url()`` function can be used instead of a tuple as an argument to -``patterns()``. This is convenient if you wish to specify a name without the +**New in Django development version** + +You can use the ``url()`` function, instead of a tuple, as an argument to +``patterns()``. This is convenient if you want to specify a name without the optional extra arguments dictionary. For example:: urlpatterns = patterns('', @@ -498,26 +499,40 @@ the view prefix (as explained in "The view prefix" above) will have no effect. Naming URL patterns =================== -**New in development version** +**New in Django development version** + +It's fairly common to use the same view function in multiple URL patterns in +your URLconf. For example, these two URL patterns both point to the ``archive`` +view:: + + urlpatterns = patterns('', + (r'/archive/(\d{4})/$', archive), + (r'/archive-summary/(\d{4})/$', archive, {'summary': True}), + ) + +This is completely valid, but it leads to problems when you try to do reverse +URL matching (through the ``permalink()`` decorator or the ``{% url %}`` +template tag). Continuing this example, if you wanted to retrieve the URL for +the ``archive`` view, Django's reverse URL matcher would get confused, because +*two* URLpatterns point at that view. -It is fairly common to use the same view function in multiple URL patterns in -your URLConf. This leads to problems when you come to do reverse URL matching, -because the ``permalink()`` decorator and ``{% url %}`` template tag use the -name of the view function to find a match. +To solve this problem, Django supports **named URL patterns**. That is, you can +give a name to a URL pattern in order to distinguish it from other patterns +using the same view and parameters. Then, you can use this name in reverse URL +matching. -To solve this problem, you can give a name to each of your URL patterns in -order to distinguish them from other patterns using the same views and -parameters. You can then use this name wherever you would otherwise use the -name of the view function. For example, if you URLConf contains:: +Here's the above example, rewritten to used named URL patterns:: urlpatterns = patterns('', url(r'/archive/(\d{4})/$', archive, name="full-archive"), url(r'/archive-summary/(\d{4})/$', archive, {'summary': True}, "arch-summary"), ) -...you could refer to either the summary archive view in a template as:: +With these names in place (``full-archive`` and ``arch-summary``), you can +target each pattern individually by using its name:: {% url arch-summary 1945 %} + {% url full-archive 2007 %} Even though both URL patterns refer to the ``archive`` view here, using the ``name`` parameter to ``url()`` allows you to tell them apart in templates. @@ -527,11 +542,12 @@ not restricted to valid Python names. .. note:: - Make sure that when you name your URLs, you use names that are unlikely to - clash with any other application's choice of names. If you call your URL - pattern *comment* and another application does the same thing, there is no - guarantee which URL will be inserted into your template when you use this - name. Putting a prefix on your URL names, perhaps derived from - the application name, will decrease the chances of collision. Something - like *myapp-comment* is recommended over simply *comment*. + When you name your URL patterns, make sure you use names that are unlikely + to clash with any other application's choice of names. If you call your URL + pattern ``comment``, and another application does the same thing, there's + no guarantee which URL will be inserted into your template when you use + this name. + Putting a prefix on your URL names, perhaps derived from the application + name, will decrease the chances of collision. We recommend something like + ``myapp-comment`` instead of ``comment``. diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index 535a7036f4..14ec96940f 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -159,7 +159,7 @@ represented by a ChoiceField. -Article: +Article: Categories: -
  • Article:
  • +
  • Article:
  • Categories:
  • -
  • Article:
  • +
  • Article:
  • Categories:
  • -
  • Article:
  • +
  • Article:
  • Categories:
  • -
  • Article:
  • +
  • Article:
  • Categories: @@ -247,7 +247,7 @@ as its choices. # USSocialSecurityNumberField ################################################# ->>> from django.contrib.localflavor.usa.forms import USSocialSecurityNumberField +>>> from django.contrib.localflavor.us.forms import USSocialSecurityNumberField >>> f = USSocialSecurityNumberField() >>> f.clean('987-65-4330') u'987-65-4330' @@ -882,4 +882,134 @@ u'9786324830D-6104243-0910271-2' Traceback (most recent call last): ... ValidationError: [u'Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.'] + +## AUPostCodeField ########################################################## + +A field that accepts a four digit Australian post code. + +>>> from django.contrib.localflavor.au.forms import AUPostCodeField +>>> f = AUPostCodeField() +>>> f.clean('1234') +u'1234' +>>> f.clean('2000') +u'2000' +>>> f.clean('abcd') +Traceback (most recent call last): +... +ValidationError: [u'Enter a 4 digit post code.'] +>>> f.clean('20001') +Traceback (most recent call last): +... +ValidationError: [u'Enter a 4 digit post code.'] +>>> f.clean(None) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] +>>> f.clean('') +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f = AUPostCodeField(required=False) +>>> f.clean('1234') +u'1234' +>>> f.clean('2000') +u'2000' +>>> f.clean('abcd') +Traceback (most recent call last): +... +ValidationError: [u'Enter a 4 digit post code.'] +>>> f.clean('20001') +Traceback (most recent call last): +... +ValidationError: [u'Enter a 4 digit post code.'] +>>> f.clean(None) +u'' +>>> f.clean('') +u'' + +## AUPhoneNumberField ######################################################## + +A field that accepts a 10 digit Australian phone number. +llows spaces and parentheses around area code. + +>>> from django.contrib.localflavor.au.forms import AUPhoneNumberField +>>> f = AUPhoneNumberField() +>>> f.clean('1234567890') +u'1234567890' +>>> f.clean('0213456789') +u'0213456789' +>>> f.clean('02 13 45 67 89') +u'0213456789' +>>> f.clean('(02) 1345 6789') +u'0213456789' +>>> f.clean('(02) 1345-6789') +u'0213456789' +>>> f.clean('(02)1345-6789') +u'0213456789' +>>> f.clean('0408 123 456') +u'0408123456' +>>> f.clean('123') +Traceback (most recent call last): +... +ValidationError: [u'Phone numbers must contain 10 digits.'] +>>> f.clean('1800DJANGO') +Traceback (most recent call last): +... +ValidationError: [u'Phone numbers must contain 10 digits.'] +>>> f.clean(None) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] +>>> f.clean('') +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f = AUPhoneNumberField(required=False) +>>> f.clean('1234567890') +u'1234567890' +>>> f.clean('0213456789') +u'0213456789' +>>> f.clean('02 13 45 67 89') +u'0213456789' +>>> f.clean('(02) 1345 6789') +u'0213456789' +>>> f.clean('(02) 1345-6789') +u'0213456789' +>>> f.clean('(02)1345-6789') +u'0213456789' +>>> f.clean('0408 123 456') +u'0408123456' +>>> f.clean('123') +Traceback (most recent call last): +... +ValidationError: [u'Phone numbers must contain 10 digits.'] +>>> f.clean('1800DJANGO') +Traceback (most recent call last): +... +ValidationError: [u'Phone numbers must contain 10 digits.'] +>>> f.clean(None) +u'' +>>> f.clean('') +u'' + +## AUStateSelect ############################################################# + +AUStateSelect is a Select widget that uses a list of Australian +states/territories as its choices. + +>>> from django.contrib.localflavor.au.forms import AUStateSelect +>>> f = AUStateSelect() +>>> print f.render('state', 'NSW') + """ diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index e78a4d0ec3..4521d17d7f 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -193,30 +193,30 @@ u'' +u'' >>> w.render('msg', None) -u'' +u'' >>> w.render('msg', 'value') -u'' +u'' >>> w.render('msg', 'some "quoted" & ampersanded value') -u'' ->>> w.render('msg', 'value', attrs={'class': 'pretty'}) -u'' +u'' +>>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20}) +u'' You can also pass 'attrs' to the constructor: >>> w = Textarea(attrs={'class': 'pretty'}) >>> w.render('msg', '') -u'' +u'' >>> w.render('msg', 'example') -u'' +u'' 'attrs' passed to render() get precedence over those passed to the constructor: >>> w = Textarea(attrs={'class': 'pretty'}) >>> w.render('msg', '', attrs={'class': 'special'}) -u'' +u'' >>> w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}) -u'' +u'' # CheckboxInput Widget ######################################################## @@ -1966,12 +1966,12 @@ Any Field can have a Widget class passed to its constructor: >>> print f['subject'] >>> print f['message'] - + as_textarea(), as_text() and as_hidden() are shortcuts for changing the output widget type: >>> f['subject'].as_textarea() -u'' +u'' >>> f['message'].as_text() u'' >>> f['message'].as_hidden() @@ -1991,7 +1991,7 @@ as_hidden(): u'' >>> f = ContactForm({'subject': 'Hello', 'message': 'I love you.'}, auto_id=False) >>> f['subject'].as_textarea() -u'' +u'' >>> f['message'].as_text() u'' >>> f['message'].as_hidden() -- cgit v1.3