Index: django/contrib/localflavor/br/forms.py
===================================================================
--- django/contrib/localflavor/br/forms.py	(revision 10620)
+++ django/contrib/localflavor/br/forms.py	(working copy)
@@ -86,6 +86,15 @@
     """
     This field validate a CPF number or a CPF string. A CPF number is
     compounded by XXX.XXX.XXX-VD. The two last digits are check digits.
+    By default, the cleaned value is in the same format as entered. 
+    If you'd like to keep a unique format for cleaned values use
+    the parameter "return_format" to provide the string format of the cleaned
+    value.
+    
+    You can use one of these class constants to the "return_format" parameter:
+    
+      DIGITS_ONLY = '%s%s%s%s' (ex. XXXXXXXXXXVD)
+      DOTS_AND_DASH = '%s.%s.%s-%s' (ex. XXX.XXX.XXX-VD)
 
     More information:
     http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
@@ -96,9 +105,14 @@
         'digits_only': _("This field requires only numbers."),
     }
 
-    def __init__(self, *args, **kwargs):
-        super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs)
+    DIGITS_ONLY = u'%s%s%s%s'
+    DOTS_AND_DASH = u'%s.%s.%s-%s'
 
+    def __init__(self, return_format=None, *args, **kwargs):
+        self.return_format = return_format
+        super(BRCPFField, self).__init__(max_length=14, min_length=11, 
+                                         *args, **kwargs)
+
     def clean(self, value):
         """
         Value can be either a string in the format XXX.XXX.XXX-XX or an
@@ -116,8 +130,12 @@
             raise ValidationError(self.error_messages['digits_only'])
         if len(value) != 11:
             raise ValidationError(self.error_messages['max_digits'])
+
+        # exclude cases of repeated digits form 0 to 9
+        if value in [str(d) * 11 for d in range(10)]:
+            raise ValidationError(self.error_messages['invalid'])
+
         orig_dv = value[-2:]
-
         new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
         new_1dv = DV_maker(new_1dv % 11)
         value = value[:-2] + str(new_1dv) + value[-1]
@@ -127,15 +145,42 @@
         if value[-2:] != orig_dv:
             raise ValidationError(self.error_messages['invalid'])
 
+        # return a formatted string if asked
+        if self.return_format:
+            value = re.sub(r'[-\.]', '', orig_value)
+            return self.return_format % tuple(re.findall(r'(\d{2,3})', value))
+
         return orig_value
 
-class BRCNPJField(Field):
+class BRCNPJField(CharField):
+    """
+    This field validates a CNPJ number or a CNPJ string. A CNPJ number is
+    compounded by XX.XXX.XXX/XXXX-XX.
+    By default, the cleaned value is in the same format as entered. 
+    If you'd like to keep a unique format for cleaned values use
+    the parameter "return_format" to provide the string format of the cleaned
+    value.
+    
+    You can use one of these class constants to the "return_format" parameter:
+    
+      DIGITS_ONLY = '%s%s%s%s%s' (ex. XXXXXXXXXXXXXX)
+      DOTS_SLASH_DASH = '%s.%s.%s/%s-%s' (ex. XX.XXX.XXX/XXXX-XX)
+    
+    """
     default_error_messages = {
         'invalid': _("Invalid CNPJ number."),
         'digits_only': _("This field requires only numbers."),
         'max_digits': _("This field requires at least 14 digits"),
     }
 
+    DIGITS_ONLY = u'%s%s%s%s%s'
+    DOTS_SLASH_DASH = u'%s.%s.%s/%s-%s'
+    
+    def __init__(self, return_format=None, *args, **kwargs):
+        self.return_format = return_format
+        super(BRCNPJField, self).__init__(max_length=18, min_length=14, 
+                                          *args, **kwargs)    
+
     def clean(self, value):
         """
         Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a
@@ -163,5 +208,10 @@
         value = value[:-1] + str(new_2dv)
         if value[-2:] != orig_dv:
             raise ValidationError(self.error_messages['invalid'])
+            
+        if self.return_format:
+            value = re.sub('[-/\.]', '', orig_value)
+            m = re.match(r'(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})', value)
+            return self.return_format % tuple(m.groups())
 
         return orig_value
Index: tests/regressiontests/forms/localflavor/br.py
===================================================================
--- tests/regressiontests/forms/localflavor/br.py	(revision 10620)
+++ tests/regressiontests/forms/localflavor/br.py	(working copy)
@@ -85,11 +85,11 @@
 ...
 ValidationError: [u'Invalid CNPJ number.']
 >>> f.clean('64.132.916/0001-88')
-'64.132.916/0001-88'
+u'64.132.916/0001-88'
 >>> f.clean('64-132-916/0001-88')
-'64-132-916/0001-88'
+u'64-132-916/0001-88'
 >>> f.clean('64132916/0001-88')
-'64132916/0001-88'
+u'64132916/0001-88'
 >>> f.clean('64.132.916/0001-XX')
 Traceback (most recent call last):
 ...
@@ -97,6 +97,47 @@
 >>> f = BRCNPJField(required=False)
 >>> f.clean('')
 u''
+>>> f.clean('64.132.916/0001-8')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires at least 14 digits']
+>>> f.clean('6413291600018')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 14 characters (it has 13).']
+>>> f.clean('64.132.916/0001-889')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 18 characters (it has 19).']
+>>> from django.contrib.localflavor.br.forms import BRCNPJField
+>>> f = BRCNPJField(return_format=BRCNPJField.DIGITS_ONLY)
+>>> f.clean('12-345-678/9012-10')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CNPJ number.']
+>>> f.clean('64.132.916/0001-88')
+u'64132916000188'
+>>> f.clean('64132916000188')
+u'64132916000188'
+>>> f.clean('64132916/0001-88')
+u'64132916000188'
+>>> f = BRCNPJField(return_format=BRCNPJField.DOTS_SLASH_DASH)
+>>> f.clean('64132916/0001-88')
+u'64.132.916/0001-88'
+>>> f.clean('64132916000188')
+u'64.132.916/0001-88'
+>>> f.clean('64.132.916/0001-88')
+u'64.132.916/0001-88'
+>>> f = BRCNPJField(return_format='%s%s%s/%s%s')
+>>> f.clean('64132916/0001-88')
+u'64132916/000188'
+>>> f.clean('64132916000188')
+u'64132916/000188'
+>>> f.clean('64.132.916/0001-88')
+u'64132916/000188'
+>>> f = BRCNPJField(return_format='%s%s%s/%s%s', required=False)
+>>> f.clean('')
+u''
 
 # BRCPFField #################################################################
 
@@ -151,6 +192,40 @@
 u''
 >>> f.clean(None)
 u''
+>>> f = BRCPFField(return_format=BRCPFField.DIGITS_ONLY)
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('663.256.017-26')
+u'66325601726'
+>>> f.clean('66325601726')
+u'66325601726'
+>>> f = BRCPFField(return_format=BRCPFField.DOTS_AND_DASH)
+>>> f.clean('663.256.017-26')
+u'663.256.017-26'
+>>> f.clean('66325601726')
+u'663.256.017-26'
+>>> f = BRCPFField(return_format='%s%s%s-%s')
+>>> f.clean('663.256.017-26')
+u'663256017-26'
+>>> f.clean('66325601726')
+u'663256017-26'
+>>> f = BRCPFField(return_format='%s%s%s-%s', required=False)
+>>> f.clean('')
+u''
+>>> f.clean('000.000.000-00')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CPF number.']
+>>> f.clean('444.444.444-44')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CPF number.']
+>>> f.clean('999.999.999-99')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CPF number.']
 
 # BRPhoneNumberField #########################################################
 
