Ticket #811: ipv6.diff

File ipv6.diff, 13.9 KB (added by Johann Queuniet <johann.queuniet@…>, 16 years ago)

IPv4/IPv6 field with doc, tests and integration with new/oldforms

  • django/oldforms/__init__.py

     
    933933
    934934    def isValidIPAddress(self, field_data, all_data):
    935935        try:
    936             validators.isValidIPAddress4(field_data, all_data)
     936            validators.isValidIP4Address(field_data, all_data)
    937937        except validators.ValidationError, e:
    938938            raise validators.CriticalValidationError, e.messages
    939939
     
    941941        return data or None
    942942    html2python = staticmethod(html2python)
    943943
     944class IP6AddressField(IPAddressField):
     945    def __init__(self, field_name, length=39, max_length=39, is_required=False, validator_list=None):
     946        if validator_list is None: validator_list = []
     947        validator_list = [self.isValidIPAddress] + validator_list
     948        TextField.__init__(self, field_name, length=length, max_length=max_length,
     949            is_required=is_required, validator_list=validator_list)
     950
     951    def isValidIPAddress(self, field_data, all_data):
     952        try:
     953            validators.isValidIPAddress(field_data, all_data)
     954        except validators.ValidationError, e:
     955            raise validators.CriticalValidationError, e.messages
     956
     957    def html2python(data):
     958        return data or None
     959    html2python = staticmethod(html2python)
     960
    944961####################
    945962# MISCELLANEOUS    #
    946963####################
  • django/db/models/fields/__init__.py

     
    894894        defaults.update(kwargs)
    895895        return super(IPAddressField, self).formfield(**defaults)
    896896
     897class IP6AddressField(Field):
     898    empty_strings_allowed = False
     899    def __init__(self, *args, **kwargs):
     900        kwargs['max_length'] = 39
     901        Field.__init__(self, *args, **kwargs)
     902
     903    def get_manipulator_field_objs(self):
     904        return [oldforms.IP6AddressField]
     905
     906    def validate(self, field_data, all_data):
     907        validators.isValidIPAddress(field_data, None)
     908
     909    def formfield(self, **kwargs):
     910        defaults = {'form_class': forms.IP6AddressField}
     911        defaults.update(kwargs)
     912        return super(IP6AddressField, self).formfield(**defaults)
     913
     914
    897915class NullBooleanField(Field):
    898916    empty_strings_allowed = False
    899917    def __init__(self, *args, **kwargs):
  • django/db/backends/ado_mssql/creation.py

     
    1212    'ImageField':        'varchar(%(max_length)s)',
    1313    'IntegerField':      'int',
    1414    'IPAddressField':    'char(15)',
     15    'IP6AddressField':   'char(39)',
    1516    'NullBooleanField':  'bit',
    1617    'OneToOneField':     'int',
    1718    'PhoneNumberField':  'varchar(20)',
  • django/db/backends/postgresql/introspection.py

     
    7575    23: 'IntegerField',
    7676    25: 'TextField',
    7777    701: 'FloatField',
    78     869: 'IPAddressField',
     78    869: 'IP6AddressField',
    7979    1043: 'CharField',
    8080    1082: 'DateField',
    8181    1083: 'TimeField',
  • django/db/backends/postgresql/creation.py

     
    1616    'ImageField':        'varchar(%(max_length)s)',
    1717    'IntegerField':      'integer',
    1818    'IPAddressField':    'inet',
     19    'IP6AddressField':   'inet',
    1920    'NullBooleanField':  'boolean',
    2021    'OneToOneField':     'integer',
    2122    'PhoneNumberField':  'varchar(20)',
  • django/db/backends/mysql_old/creation.py

     
    1616    'ImageField':        'varchar(%(max_length)s)',
    1717    'IntegerField':      'integer',
    1818    'IPAddressField':    'char(15)',
     19    'IP6AddressField':   'char(39)',
    1920    'NullBooleanField':  'bool',
    2021    'OneToOneField':     'integer',
    2122    'PhoneNumberField':  'varchar(20)',
  • django/db/backends/sqlite3/creation.py

     
    1515    'ImageField':                   'varchar(%(max_length)s)',
    1616    'IntegerField':                 'integer',
    1717    'IPAddressField':               'char(15)',
     18    'IP6AddressField':              'char(39)',
    1819    'NullBooleanField':             'bool',
    1920    'OneToOneField':                'integer',
    2021    'PhoneNumberField':             'varchar(20)',
  • django/db/backends/mysql/creation.py

     
    1616    'ImageField':        'varchar(%(max_length)s)',
    1717    'IntegerField':      'integer',
    1818    'IPAddressField':    'char(15)',
     19    'IPAddressField':    'char(39)',
    1920    'NullBooleanField':  'bool',
    2021    'OneToOneField':     'integer',
    2122    'PhoneNumberField':  'varchar(20)',
  • django/db/backends/oracle/creation.py

     
    1919    'ImageField':                   'NVARCHAR2(%(max_length)s)',
    2020    'IntegerField':                 'NUMBER(11)',
    2121    'IPAddressField':               'VARCHAR2(15)',
     22    'IP6AddressField':              'VARCHAR2(39)',
    2223    'NullBooleanField':             'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
    2324    'OneToOneField':                'NUMBER(11)',
    2425    'PhoneNumberField':             'VARCHAR2(20)',
  • django/db/backends/postgresql_psycopg2/introspection.py

     
    7272    23: 'IntegerField',
    7373    25: 'TextField',
    7474    701: 'FloatField',
    75     869: 'IPAddressField',
     75    869: 'IP6AddressField',
    7676    1043: 'CharField',
    7777    1082: 'DateField',
    7878    1083: 'TimeField',
  • django/core/validators.py

     
    106106        except ValidationError:
    107107            raise ValidationError, _("Enter valid e-mail addresses separated by commas.")
    108108
    109 def isValidIPAddress4(field_data, all_data):
     109def isValidIP4Address(field_data, all_data):
    110110    if not ip4_re.search(field_data):
     111        raise ValidationError, _("Please enter a valid IPv4 address.")
     112
     113def isValidIPAddress(field_data, all_data):
     114    import IPy
     115    try:
     116        IPy.parseAddress(field_data)
     117    except ValueError:
    111118        raise ValidationError, _("Please enter a valid IP address.")
    112119
    113120def isNotEmpty(field_data, all_data):
  • django/newforms/fields.py

     
    1616except NameError:
    1717    from sets import Set as set
    1818
     19import IPy
     20
    1921from django.utils.translation import ugettext_lazy as _
    2022from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str
    2123
     
    3133    'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
    3234    'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
    3335    'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
    34     'SplitDateTimeField', 'IPAddressField',
     36    'SplitDateTimeField', 'IPAddressField', 'IP6AddressField',
    3537)
    3638
    3739# These values, if given to to_python(), will trigger the self.required check.
     
    754756
    755757    def __init__(self, *args, **kwargs):
    756758        super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs)
     759
     760class IP6AddressField(CharField):
     761    def __init__(self, *args, **kwargs):
     762        super(IP6AddressField, self).__init__(39, 3, *args, **kwargs)
     763
     764    def clean(self, value):
     765        value = super(IP6AddressField, self).clean(value)
     766        if value == u'':
     767            return value
     768        try:
     769            IPy.parseAddress(value)
     770        except ValueError:
     771            raise ValidationError(_(u'Enter a valid IP address.'))
     772        return value
  • tests/regressiontests/forms/extra.py

     
    310310...
    311311ValidationError: [u'Enter a valid IPv4 address.']
    312312
     313# IP6AddressField ##################################################################
     314
     315>>> f = IP6AddressField()
     316>>> f.clean('')
     317Traceback (most recent call last):
     318...
     319ValidationError: [u'This field is required.']
     320>>> f.clean(None)
     321Traceback (most recent call last):
     322...
     323ValidationError: [u'This field is required.']
     324>>> f.clean('127.0.0.1')
     325u'127.0.0.1'
     326>>> f.clean('2a01:05d8:25ae:9451:020d:39bc:21e6:8cab')
     327u'2a01:05d8:25ae:9451:020d:39bc:21e6:8cab'
     328>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:21e6:8cab')
     329u'2a01:5d8:25ae:9451:20d:39bc:21e6:8cab'
     330>>> f.clean('::1')
     331u'::1'
     332>>> f.clean('::ffff:88.191.32.1')
     333u'::ffff:88.191.32.1'
     334>>> f.clean('foo')
     335Traceback (most recent call last):
     336...
     337ValidationError: [u'Enter a valid IP address.']
     338>>> f.clean('127.0.0.')
     339Traceback (most recent call last):
     340...
     341ValidationError: [u'Enter a valid IP address.']
     342>>> f.clean('::1:')
     343Traceback (most recent call last):
     344...
     345ValidationError: [u'Enter a valid IP address.']
     346>>> f.clean('1.2.3.4.5')
     347Traceback (most recent call last):
     348...
     349ValidationError: [u'Enter a valid IP address.']
     350>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:21e6:8cab:fb2c')
     351Traceback (most recent call last):
     352...
     353ValidationError: [u'Ensure this value has at most 39 characters (it has 42).']
     354>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:1e6:cab:b2c')
     355Traceback (most recent call last):
     356...
     357ValidationError: [u'Enter a valid IP address.']
     358>>> f.clean('256.125.1.5')
     359Traceback (most recent call last):
     360...
     361ValidationError: [u'Enter a valid IP address.']
     362>>> f.clean('::12345')
     363Traceback (most recent call last):
     364...
     365ValidationError: [u'Enter a valid IP address.']
     366
     367>>> f = IP6AddressField(required=False)
     368>>> f.clean('')
     369u''
     370>>> f.clean(None)
     371u''
     372>>> f.clean('127.0.0.1')
     373u'127.0.0.1'
     374>>> f.clean('foo')
     375Traceback (most recent call last):
     376...
     377ValidationError: [u'Enter a valid IP address.']
     378>>> f.clean('127.0.0.')
     379Traceback (most recent call last):
     380...
     381ValidationError: [u'Enter a valid IP address.']
     382>>> f.clean('1.2.3.4.5')
     383Traceback (most recent call last):
     384...
     385ValidationError: [u'Enter a valid IP address.']
     386>>> f.clean('256.125.1.5')
     387Traceback (most recent call last):
     388...
     389ValidationError: [u'Enter a valid IP address.']
     390
     391
    313392#################################
    314393# Tests of underlying functions #
    315394#################################
  • docs/newforms.txt

     
    13901390      expression.
    13911391    * Error message keys: ``required``, ``invalid``
    13921392
     1393``IP6AddressField``
     1394~~~~~~~~~~~~~~~~~~
     1395
     1396    * Default widget: ``TextInput``
     1397    * Empty value: ``''`` (an empty string)
     1398    * Normalizes to: A Unicode object.
     1399    * Validates that the given value is a valid IPv4 or IPv6 address, using
     1400      IPy
     1401    * Error message keys: ``required``, ``invalid``
     1402
    13931403``MultipleChoiceField``
    13941404~~~~~~~~~~~~~~~~~~~~~~~
    13951405
  • docs/model-api.txt

     
    388388
    389389The admin represents this as an ``<input type="text">`` (a single-line input).
    390390
     391``IP6AddressField``
     392~~~~~~~~~~~~~~~~~~
     393
     394An IPv6 or IPv4 address, in string format (i.e. "24.124.1.30",
     395"2002:58bf:278c::1", "::ffff:88.191.52.1").
     396
     397The admin represents this as an ``<input type="text">`` (a single-line input).
     398
     399Requires `IPy`_.
     400
     401.. _IPy: http://software.inl.fr//trac/wiki/IPy
     402
    391403``NullBooleanField``
    392404~~~~~~~~~~~~~~~~~~~~
    393405
  • docs/modelforms.txt

     
    5858    ``ImageField``                   ``ImageField``
    5959    ``IntegerField``                 ``IntegerField``
    6060    ``IPAddressField``               ``IPAddressField``
     61    ``IP6AddressField``               ``IP6AddressField``
    6162    ``ManyToManyField``              ``ModelMultipleChoiceField`` (see
    6263                                     below)
    6364    ``NullBooleanField``             ``CharField``
  • docs/form_for_model.txt

     
    6565    ``ImageField``                   ``ImageField``
    6666    ``IntegerField``                 ``IntegerField``
    6767    ``IPAddressField``               ``IPAddressField``
     68    ``IP6AddressField``               ``IP6AddressField``
    6869    ``ManyToManyField``              ``ModelMultipleChoiceField`` (see
    6970                                     below)
    7071    ``NullBooleanField``             ``CharField``
Back to Top