diff --git a/AUTHORS b/AUTHORS index ad269d3f3bd..9e782455067 100644 --- a/AUTHORS +++ b/AUTHORS @@ -179,6 +179,7 @@ answer newbie questions, and generally made Django that much better: SmileyChris smurf@smurf.noris.de sopel + Wiliam Alves de Souza Georgi Stanojevski Thomas Steinacher nowell strite diff --git a/django/contrib/localflavor/br/__init__.py b/django/contrib/localflavor/br/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/django/contrib/localflavor/br/br_states.py b/django/contrib/localflavor/br/br_states.py new file mode 100644 index 00000000000..c6ce0a1bb7b --- /dev/null +++ b/django/contrib/localflavor/br/br_states.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +""" +A brazilian mapping of state misspellings/abbreviations to normalized +abbreviations, and an alphabetical list of states for use as `choices +in a formfield. + +This exists in this standalone file so that it's only imported into +memory when explicitly needed. +""" + +STATE_CHOICES = ( + ('AC', 'Acre'), + ('AL', 'Alagoas'), + ('AP', u'Amapá'), + ('AM', 'Amazonas'), + ('BA', 'Bahia'), + ('CE', u'Ceará'), + ('DF', 'Distrito Federal'), + ('ES', u'Espírito Santo'), + ('GO', u'Goiás'), + ('MA', u'Maranhão'), + ('MT', 'Mato Grosso'), + ('MS', 'Mato Grosso do Sul'), + ('MG', 'Minas Gerais'), + ('PA', u'Pará'), + ('PB', u'Paraíba'), + ('PR', u'Paraná'), + ('PE', 'Pernambuco'), + ('PI', u'Piauí'), + ('RJ', 'Rio de Janeiro'), + ('RN', 'Rio Grande do Norte'), + ('RS', 'Rio Grande do Sul'), + ('RO', u'Rondônia'), + ('RR', 'Roraima'), + ('SC', 'Santa Catarina'), + ('SP', u'São Paulo'), + ('SE', 'Sergipe'), + ('TO', 'Tocantins'), +) diff --git a/django/contrib/localflavor/br/forms.py b/django/contrib/localflavor/br/forms.py new file mode 100644 index 00000000000..d3ca28f0538 --- /dev/null +++ b/django/contrib/localflavor/br/forms.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +""" +BR-specific Form helpers +""" + +from django.newforms import ValidationError +from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES +from django.newforms.util import smart_unicode +from django.utils.translation import gettext +import re + +phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$') + +class BRZipCodeField(RegexField): + def __init__(self, *args, **kwargs): + super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$', + max_length=None, min_length=None, + error_message=u'Informe um código postal no formato XXXXX-XXX.', + *args, **kwargs) + +class BRPhoneNumberField(Field): + def clean(self, value): + super(BRPhoneNumberField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + value = re.sub('(\(|\)|\s+)', '', smart_unicode(value)) + m = phone_digits_re.search(value) + if m: + return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3)) + raise ValidationError(u'Números de telefone devem estar no formato XX-XXXX-XXXX.') + +class BRStateSelect(Select): + """ + A Select widget that uses a list of brazilian states/territories + as its choices. + """ + def __init__(self, attrs=None): + from br_states import STATE_CHOICES # relative import + super(BRStateSelect, self).__init__(attrs, choices=STATE_CHOICES) diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index b2d66469c40..7f9f7fcbefa 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -3974,6 +3974,120 @@ u'' >>> f.clean('') u'' +# BRZipCodeField ############################################################ +>>> from django.contrib.localflavor.br.forms import BRZipCodeField +>>> f = BRZipCodeField() +>>> f.clean('12345-123') +u'12345-123' +>>> f.clean('12345_123') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('1234-123') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('abcde-abc') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('12345-') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('-123') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('') +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] +>>> f.clean(None) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f = BRZipCodeField(required=False) +>>> f.clean(None) +u'' +>>> f.clean('') +u'' +>>> f.clean('-123') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('12345-') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('abcde-abc') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('1234-123') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('12345_123') +Traceback (most recent call last): +... +ValidationError: [u'Informe um c\xf3digo postal no formato XXXXX-XXX.'] +>>> f.clean('12345-123') +u'12345-123' + +# BRPhoneNumberField ######################################################### + +>>> from django.contrib.localflavor.br.forms import BRPhoneNumberField +>>> f = BRPhoneNumberField() +>>> f.clean('41-3562-3464') +u'41-3562-3464' +>>> f.clean('4135623464') +u'41-3562-3464' +>>> f.clean('41 3562-3464') +u'41-3562-3464' +>>> f.clean('41 3562 3464') +u'41-3562-3464' +>>> f.clean('(41) 3562 3464') +u'41-3562-3464' +>>> f.clean('41.3562.3464') +u'41-3562-3464' +>>> f.clean('41.3562-3464') +u'41-3562-3464' +>>> f.clean(' (41) 3562.3464') +u'41-3562-3464' +>>> f.clean(None) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] +>>> f.clean('') +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f = BRPhoneNumberField(required=False) +>>> f.clean('') +u'' +>>> f.clean(None) +u'' +>>> f.clean(' (41) 3562.3464') +u'41-3562-3464' +>>> f.clean('41.3562-3464') +u'41-3562-3464' +>>> f.clean('(41) 3562 3464') +u'41-3562-3464' +>>> f.clean('4135623464') +u'41-3562-3464' +>>> f.clean('41 3562-3464') +u'41-3562-3464' + +# BRStateSelect ############################################################## + +>>> from django.contrib.localflavor.br.forms import BRStateSelect +>>> w = BRStateSelect() +>>> w.render('states', 'PR') +u'' + ################################# # Tests of underlying functions # #################################