Code

Ticket #5670: ukpostcodefield.diff

File ukpostcodefield.diff, 3.7 KB (added by scott@…, 7 years ago)

Patch and tests

Line 
1Index: django/contrib/localflavor/uk/forms.py
2===================================================================
3--- django/contrib/localflavor/uk/forms.py      (revision 6447)
4+++ django/contrib/localflavor/uk/forms.py      (working copy)
5@@ -1,19 +1,33 @@
6 """
7 UK-specific Form helpers
8 """
9+import re
10 
11-from django.newforms.fields import RegexField
12+from django.newforms.fields import CharField
13+from django.newforms import ValidationError
14 from django.utils.translation import ugettext
15 
16-class UKPostcodeField(RegexField):
17+class UKPostcodeField(CharField):
18     """
19     A form field that validates its input is a UK postcode.
20+   
21+    Uppercases the value and adds space in correct place if required.
22 
23     The regular expression used is sourced from the schema for British Standard
24     BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd
25     """
26-    def __init__(self, *args, **kwargs):
27-        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})$',
28-            max_length=None, min_length=None,
29-            error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
30-            *args, **kwargs)
31+    OUTCODE_PATTERN = '[A-PR-UWYZ]([0-9]{1,2}|([A-HIK-Y][0-9](|[0-9]|[ABEHMNPRVWXY]))|[0-9][A-HJKSTUW])'
32+    INCODE_PATTERN = '[0-9][ABD-HJLNP-UW-Z]{2}'
33+    POSTCODE_REGEX = re.compile(r'^(GIR 0AA|%s %s)$' % (OUTCODE_PATTERN, INCODE_PATTERN))
34+    SPACE_REGEX = re.compile(r' *(%s)$' % INCODE_PATTERN)
35+
36+    def clean(self, value):
37+        value = super(UKPostcodeField, self).clean(value)
38+        if value == u'':
39+            return value
40+        postcode = value.upper().strip()
41+        # Put a single space before the incode (second part).
42+        postcode = self.SPACE_REGEX.sub(r' \1', postcode)
43+        if not self.POSTCODE_REGEX.search(postcode):
44+            raise ValidationError(ugettext(u'Enter a valid postcode.'))
45+        return postcode
46Index: tests/regressiontests/forms/localflavor/uk.py
47===================================================================
48--- tests/regressiontests/forms/localflavor/uk.py       (revision 6447)
49+++ tests/regressiontests/forms/localflavor/uk.py       (working copy)
50@@ -12,13 +12,15 @@
51 >>> f.clean('GIR 0AA')
52 u'GIR 0AA'
53 >>> f.clean('BT324PX')
54+u'BT32 4PX'
55+>>> f.clean('1NV 4L1D')
56 Traceback (most recent call last):
57 ...
58-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
59->>> f.clean('1NV 4L1D')
60+ValidationError: [u'Enter a valid postcode.']
61+>>> f.clean('1NV4L1D')
62 Traceback (most recent call last):
63 ...
64-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
65+ValidationError: [u'Enter a valid postcode.']
66 >>> f.clean(None)
67 Traceback (most recent call last):
68 ...
69@@ -27,6 +29,18 @@
70 Traceback (most recent call last):
71 ...
72 ValidationError: [u'This field is required.']
73+>>> f.clean(' so11aa ')
74+u'SO1 1AA'
75+>>> f.clean(' so1  1aa ')
76+u'SO1 1AA'
77+>>> f.clean('G2 3wt')
78+u'G2 3WT'
79+>>> f.clean('EC1A 1BB')
80+u'EC1A 1BB'
81+>>> f.clean('Ec1a1BB')
82+u'EC1A 1BB'
83+>>> f.clean(' b0gUS')
84+ValidationError: [u'Enter a valid postcode.']
85 
86 >>> f = UKPostcodeField(required=False)
87 >>> f.clean('BT32 4PX')
88@@ -36,11 +50,9 @@
89 >>> f.clean('1NV 4L1D')
90 Traceback (most recent call last):
91 ...
92-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
93+ValidationError: [u'Enter a valid postcode.']
94 >>> f.clean('BT324PX')
95-Traceback (most recent call last):
96-...
97-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
98+u'BT32 4PX'
99 >>> f.clean(None)
100 u''
101 >>> f.clean('')