Code

Ticket #5670: ukpostcodefield2.diff

File ukpostcodefield2.diff, 3.8 KB (added by scott@…, 7 years ago)

New patch against trunk (includes tests)

Line 
1Index: django/contrib/localflavor/uk/forms.py
2===================================================================
3--- django/contrib/localflavor/uk/forms.py      (revision 6891)
4+++ django/contrib/localflavor/uk/forms.py      (working copy)
5@@ -1,23 +1,37 @@
6 """
7 UK-specific Form helpers
8 """
9+import re
10 
11-from django.newforms.fields import RegexField, Select
12+from django.newforms.fields import CharField, Select
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
46+
47 class UKCountySelect(Select):
48     """
49     A Select widget that uses a list of UK Counties/Regions as its choices.
50Index: tests/regressiontests/forms/localflavor/uk.py
51===================================================================
52--- tests/regressiontests/forms/localflavor/uk.py       (revision 6891)
53+++ tests/regressiontests/forms/localflavor/uk.py       (working copy)
54@@ -12,13 +12,15 @@
55 >>> f.clean('GIR 0AA')
56 u'GIR 0AA'
57 >>> f.clean('BT324PX')
58+u'BT32 4PX'
59+>>> f.clean('1NV 4L1D')
60 Traceback (most recent call last):
61 ...
62-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
63->>> f.clean('1NV 4L1D')
64+ValidationError: [u'Enter a valid postcode.']
65+>>> f.clean('1NV4L1D')
66 Traceback (most recent call last):
67 ...
68-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
69+ValidationError: [u'Enter a valid postcode.']
70 >>> f.clean(None)
71 Traceback (most recent call last):
72 ...
73@@ -27,7 +29,20 @@
74 Traceback (most recent call last):
75 ...
76 ValidationError: [u'This field is required.']
77-
78+>>> f.clean(' so11aa ')
79+u'SO1 1AA'
80+>>> f.clean(' so1  1aa ')
81+u'SO1 1AA'
82+>>> f.clean('G2 3wt')
83+u'G2 3WT'
84+>>> f.clean('EC1A 1BB')
85+u'EC1A 1BB'
86+>>> f.clean('Ec1a1BB')
87+u'EC1A 1BB'
88+>>> f.clean(' b0gUS')
89+Traceback (most recent call last):
90+...
91+ValidationError: [u'Enter a valid postcode.']
92 >>> f = UKPostcodeField(required=False)
93 >>> f.clean('BT32 4PX')
94 u'BT32 4PX'
95@@ -36,11 +51,9 @@
96 >>> f.clean('1NV 4L1D')
97 Traceback (most recent call last):
98 ...
99-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
100+ValidationError: [u'Enter a valid postcode.']
101 >>> f.clean('BT324PX')
102-Traceback (most recent call last):
103-...
104-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
105+u'BT32 4PX'
106 >>> f.clean(None)
107 u''
108 >>> f.clean('')