Fixed #5670 -- Changed the validation of the UK postcode widget to allow for easier input. Normalisation still returns the same things as previously. Patch from scott@staplefish.com.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6952 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-12-19 04:43:47 +00:00
parent aec96649f0
commit a35ca605d6
2 changed files with 44 additions and 15 deletions

View File

@ -2,23 +2,39 @@
UK-specific Form helpers UK-specific Form helpers
""" """
from django.newforms.fields import RegexField, Select import re
from django.newforms.fields import CharField, Select
from django.newforms import ValidationError
from django.utils.translation import ugettext from django.utils.translation import ugettext
class UKPostcodeField(RegexField): class UKPostcodeField(CharField):
""" """
A form field that validates its input is a UK postcode. A form field that validates its input is a UK postcode.
The regular expression used is sourced from the schema for British Standard The regular expression used is sourced from the schema for British Standard
BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd
The value is uppercased and a space added in the correct place, if required.
""" """
default_error_messages = { default_error_messages = {
'invalid': ugettext(u'Enter a postcode. A space is required between the two postcode parts.'), 'invalid': ugettext(u'Enter a valid postcode.'),
} }
outcode_pattern = '[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW])'
incode_pattern = '[0-9][ABD-HJLNP-UW-Z]{2}'
postcode_regex = re.compile(r'^(GIR 0AA|%s %s)$' % (outcode_pattern, incode_pattern))
space_regex = re.compile(r' *(%s)$' % incode_pattern)
def __init__(self, *args, **kwargs): def clean(self, value):
super(UKPostcodeField, self).__init__(r'^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW]) [0-9][ABD-HJLNP-UW-Z]{2})$', value = super(UKPostcodeField, self).clean(value)
max_length=None, min_length=None, *args, **kwargs) if value == u'':
return value
postcode = value.upper().strip()
# Put a single space before the incode (second part).
postcode = self.space_regex.sub(r' \1', postcode)
if not self.postcode_regex.search(postcode):
raise ValidationError(self.default_error_messages['invalid'])
return postcode
class UKCountySelect(Select): class UKCountySelect(Select):
""" """

View File

@ -12,13 +12,15 @@ u'BT32 4PX'
>>> f.clean('GIR 0AA') >>> f.clean('GIR 0AA')
u'GIR 0AA' u'GIR 0AA'
>>> f.clean('BT324PX') >>> f.clean('BT324PX')
Traceback (most recent call last): u'BT32 4PX'
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
>>> f.clean('1NV 4L1D') >>> f.clean('1NV 4L1D')
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.'] ValidationError: [u'Enter a valid postcode.']
>>> f.clean('1NV4L1D')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid postcode.']
>>> f.clean(None) >>> f.clean(None)
Traceback (most recent call last): Traceback (most recent call last):
... ...
@ -27,7 +29,20 @@ ValidationError: [u'This field is required.']
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'This field is required.'] ValidationError: [u'This field is required.']
>>> f.clean(' so11aa ')
u'SO1 1AA'
>>> f.clean(' so1 1aa ')
u'SO1 1AA'
>>> f.clean('G2 3wt')
u'G2 3WT'
>>> f.clean('EC1A 1BB')
u'EC1A 1BB'
>>> f.clean('Ec1a1BB')
u'EC1A 1BB'
>>> f.clean(' b0gUS')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid postcode.']
>>> f = UKPostcodeField(required=False) >>> f = UKPostcodeField(required=False)
>>> f.clean('BT32 4PX') >>> f.clean('BT32 4PX')
u'BT32 4PX' u'BT32 4PX'
@ -36,11 +51,9 @@ u'GIR 0AA'
>>> f.clean('1NV 4L1D') >>> f.clean('1NV 4L1D')
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.'] ValidationError: [u'Enter a valid postcode.']
>>> f.clean('BT324PX') >>> f.clean('BT324PX')
Traceback (most recent call last): u'BT32 4PX'
...
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
>>> f.clean(None) >>> f.clean(None)
u'' u''
>>> f.clean('') >>> f.clean('')