Ticket #8798: r17015-dephonenumberfield.diff

File r17015-dephonenumberfield.diff, 6.0 KB (added by Sebastian Goll, 13 years ago)
  • docs/ref/contrib/localflavor.txt

     
    551551
    552552.. _Personalausweis: http://de.wikipedia.org/wiki/Personalausweis
    553553
     554.. class:: de.forms.DEPhoneNumberField
     555
     556    A form field that validates input as a German telephone
     557    number. `Several formats`_ are accepted. The field value is
     558    normalized to format 0301234567, which always includes the area
     559    code with a leading zero and does not include the (optional)
     560    country code. Extra spaces, hyphens, and parentheses in the phone
     561    number are removed.
     562
     563.. _Several formats: http://de.wikipedia.org/wiki/Rufnummer#Schreibweisen
     564
    554565.. class:: de.forms.DEZipCodeField
    555566
    556567    A form field that validates input as a German zip code. Valid codes
  • tests/regressiontests/localflavor/de/tests.py

     
    11from django.contrib.localflavor.de.forms import (DEZipCodeField, DEStateSelect,
    2     DEIdentityCardNumberField)
     2    DEIdentityCardNumberField, DEPhoneNumberField)
    33
    44from django.test import SimpleTestCase
    55
     
    4747            '0434657485D-6407276-0508137-9': error_format,
    4848        }
    4949        self.assertFieldOutput(DEIdentityCardNumberField, valid, invalid)
     50
     51    def test_DEPhoneNumberField(self):
     52        error_format = [u'Enter a valid German phone number in (030) 1234567 format.']
     53        valid = {
     54            '+49 30 12345-67': '0301234567',
     55            '+49 30 1234567': '0301234567',
     56            '+49 (30) 1234567': '0301234567',
     57            '+49-30-1234567': '0301234567',
     58            '+49 (0)30 12345-67': '0301234567',
     59            '030 12345-67': '0301234567',
     60            '(030) 12345 67': '0301234567',
     61            '0900 5 123456': '09005123456',
     62            '(0)30 12345 67': '0301234567',
     63            '(0)301234567': '0301234567',
     64            '0049 (30) 1234567': '0301234567',
     65            '0049301234567': '0301234567',
     66            '+49301234567': '0301234567',
     67            '0301234567': '0301234567',
     68        }
     69        invalid = {
     70            # Unexpected country code:
     71            '+1 30 12345-67': error_format,
     72            # Invalid area code:
     73            '(0030) 12345-67': error_format,
     74            # Ambiguous area code:
     75            '30 12345-67': error_format,
     76            # Ambiguous spacing:
     77            '(0) 301234567': error_format,
     78            # Leading zero in number:
     79            '(030) 012345-67': error_format,
     80            '030-012345-67': error_format,
     81            '(0)30 012345-67': error_format,
     82            # Too many spaces/hyphens.
     83            '+49 (0)30 12345--67': error_format,
     84            ' (0)30 12345-67': error_format,
     85            '(0)30 12345-67 ': error_format,
     86            '-030 1234567': error_format,
     87            '030  1234567': error_format,
     88        }
     89        self.assertFieldOutput(DEPhoneNumberField, valid, invalid)
     90        valid = {}
     91        invalid = {
     92            '+1 30 12345-67': [u'Just enter something!'],
     93        }
     94        kwargs = {'error_messages': {'invalid': u'Just enter something!'}}
     95        self.assertFieldOutput(DEPhoneNumberField, valid, invalid, field_kwargs=kwargs)
  • django/contrib/localflavor/de/forms.py

     
    6666        return str(calculated_checksum)[-1] == given_checksum
    6767
    6868    def clean(self, value):
    69         super(DEIdentityCardNumberField, self).clean(value)
     69        value = super(DEIdentityCardNumberField, self).clean(value)
    7070        if value in EMPTY_VALUES:
    7171            return u''
    7272        match = re.match(id_re, value)
     
    8686                raise ValidationError(self.error_messages['invalid'])
    8787
    8888        return u'%s%s-%s-%s-%s' % (residence, origin, birthday, validity, checksum)
     89
     90class DEPhoneNumberField(Field):
     91    """
     92    A German phone number.
     93
     94    The phone number may be in one of the following formats:
     95
     96      * DIN 5008: +49 30 12345-67, or 030 12345-67
     97      * E.123: +49 30 1234567, or (030) 12345 67
     98      * Microsoft: +49 (30) 1234567
     99      * RFC 3966 (URI): +49-30-1234567
     100      * Informal notation: +49 (0)30 12345-67
     101
     102    As an alternative to the optional +49, a prefix of 0049 is also
     103    acceptable. The country code (if given) is stripped. The leading
     104    zero in the area code is stated explicitly if omitted. The phone
     105    numbers above all resolve to the normalized form 0301234567.
     106
     107    For more details, see:
     108    http://de.wikipedia.org/wiki/Rufnummer#Schreibweisen
     109    """
     110    default_error_messages = {
     111        'invalid': _(u'Enter a valid German phone number in (030) 1234567 format.'),
     112    }
     113    phone_regex = re.compile(r'^(?P<country>(\+|00)49[\s-]?)?(?P<phone>(\(0?[1-9]\d{1,3}\)|0?[1-9]\d{1,3}|\(0\)[1-9]\d{1,3})([\s-]?[1-9]\d*)([\s-]?\d+)*)$')
     114    strip_regex = re.compile(r'[()\s-]')
     115
     116    def clean(self, value):
     117        value = super(DEPhoneNumberField, self).clean(value)
     118        if value in EMPTY_VALUES:
     119            return u''
     120        match = self.phone_regex.match(value)
     121        if not match:
     122            raise ValidationError(self.error_messages['invalid'])
     123        phone = self.strip_regex.sub('', match.group('phone'))
     124        # At this point, phone has at least two characters.
     125        if phone[0] != u'0':
     126            if not match.group('country'):
     127                # When no country code was given, we expect a leading
     128                # 0 in the area code to avoid any ambiguities between
     129                # numbers with and without area code.
     130                raise ValidationError(self.error_messages['invalid'])
     131            phone = u'0' + phone
     132        return phone
Back to Top