Index: django/contrib/localflavor/uk/forms.py
===================================================================
--- django/contrib/localflavor/uk/forms.py	(revision 6891)
+++ django/contrib/localflavor/uk/forms.py	(working copy)
@@ -1,23 +1,37 @@
 """
 UK-specific Form helpers
 """
+import re
 
-from django.newforms.fields import RegexField, Select
+from django.newforms.fields import CharField, Select
+from django.newforms import ValidationError
 from django.utils.translation import ugettext
 
-class UKPostcodeField(RegexField):
+class UKPostcodeField(CharField):
     """
     A form field that validates its input is a UK postcode.
+    
+    Uppercases the value and adds space in correct place if required.
 
     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
     """
-    def __init__(self, *args, **kwargs):
-        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})$',
-            max_length=None, min_length=None,
-            error_message=ugettext(u'Enter a postcode. A space is required between the two postcode parts.'),
-            *args, **kwargs)
+    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 clean(self, value):
+        value = super(UKPostcodeField, self).clean(value)
+        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(ugettext(u'Enter a valid postcode.'))
+        return postcode
+
 class UKCountySelect(Select):
     """
     A Select widget that uses a list of UK Counties/Regions as its choices.
Index: tests/regressiontests/forms/localflavor/uk.py
===================================================================
--- tests/regressiontests/forms/localflavor/uk.py	(revision 6891)
+++ tests/regressiontests/forms/localflavor/uk.py	(working copy)
@@ -12,13 +12,15 @@
 >>> f.clean('GIR 0AA')
 u'GIR 0AA'
 >>> f.clean('BT324PX')
+u'BT32 4PX'
+>>> f.clean('1NV 4L1D')
 Traceback (most recent call last):
 ...
-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
->>> f.clean('1NV 4L1D')
+ValidationError: [u'Enter a valid postcode.']
+>>> f.clean('1NV4L1D')
 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(None)
 Traceback (most recent call last):
 ...
@@ -27,7 +29,20 @@
 Traceback (most recent call last):
 ...
 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.clean('BT32 4PX')
 u'BT32 4PX'
@@ -36,11 +51,9 @@
 >>> f.clean('1NV 4L1D')
 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')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
+u'BT32 4PX'
 >>> f.clean(None)
 u''
 >>> f.clean('')
