Index: django/oldforms/__init__.py
===================================================================
--- django/oldforms/__init__.py	(revision 7053)
+++ django/oldforms/__init__.py	(working copy)
@@ -933,7 +933,7 @@
 
     def isValidIPAddress(self, field_data, all_data):
         try:
-            validators.isValidIPAddress4(field_data, all_data)
+            validators.isValidIP4Address(field_data, all_data)
         except validators.ValidationError, e:
             raise validators.CriticalValidationError, e.messages
 
@@ -941,6 +941,23 @@
         return data or None
     html2python = staticmethod(html2python)
 
+class IP6AddressField(IPAddressField):
+    def __init__(self, field_name, length=39, max_length=39, is_required=False, validator_list=None):
+        if validator_list is None: validator_list = []
+        validator_list = [self.isValidIPAddress] + validator_list
+        TextField.__init__(self, field_name, length=length, max_length=max_length,
+            is_required=is_required, validator_list=validator_list)
+
+    def isValidIPAddress(self, field_data, all_data):
+        try:
+            validators.isValidIPAddress(field_data, all_data)
+        except validators.ValidationError, e:
+            raise validators.CriticalValidationError, e.messages
+
+    def html2python(data):
+        return data or None
+    html2python = staticmethod(html2python)
+
 ####################
 # MISCELLANEOUS    #
 ####################
Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py	(revision 7053)
+++ django/db/models/fields/__init__.py	(working copy)
@@ -894,6 +894,24 @@
         defaults.update(kwargs)
         return super(IPAddressField, self).formfield(**defaults)
 
+class IP6AddressField(Field):
+    empty_strings_allowed = False
+    def __init__(self, *args, **kwargs):
+        kwargs['max_length'] = 39
+        Field.__init__(self, *args, **kwargs)
+
+    def get_manipulator_field_objs(self):
+        return [oldforms.IP6AddressField]
+
+    def validate(self, field_data, all_data):
+        validators.isValidIPAddress(field_data, None)
+
+    def formfield(self, **kwargs):
+        defaults = {'form_class': forms.IP6AddressField}
+        defaults.update(kwargs)
+        return super(IP6AddressField, self).formfield(**defaults)
+
+
 class NullBooleanField(Field):
     empty_strings_allowed = False
     def __init__(self, *args, **kwargs):
Index: django/db/backends/ado_mssql/creation.py
===================================================================
--- django/db/backends/ado_mssql/creation.py	(revision 7053)
+++ django/db/backends/ado_mssql/creation.py	(working copy)
@@ -12,6 +12,7 @@
     'ImageField':        'varchar(%(max_length)s)',
     'IntegerField':      'int',
     'IPAddressField':    'char(15)',
+    'IP6AddressField':   'char(39)',
     'NullBooleanField':  'bit',
     'OneToOneField':     'int',
     'PhoneNumberField':  'varchar(20)',
Index: django/db/backends/postgresql/introspection.py
===================================================================
--- django/db/backends/postgresql/introspection.py	(revision 7053)
+++ django/db/backends/postgresql/introspection.py	(working copy)
@@ -75,7 +75,7 @@
     23: 'IntegerField',
     25: 'TextField',
     701: 'FloatField',
-    869: 'IPAddressField',
+    869: 'IP6AddressField',
     1043: 'CharField',
     1082: 'DateField',
     1083: 'TimeField',
Index: django/db/backends/postgresql/creation.py
===================================================================
--- django/db/backends/postgresql/creation.py	(revision 7053)
+++ django/db/backends/postgresql/creation.py	(working copy)
@@ -16,6 +16,7 @@
     'ImageField':        'varchar(%(max_length)s)',
     'IntegerField':      'integer',
     'IPAddressField':    'inet',
+    'IP6AddressField':   'inet',
     'NullBooleanField':  'boolean',
     'OneToOneField':     'integer',
     'PhoneNumberField':  'varchar(20)',
Index: django/db/backends/mysql_old/creation.py
===================================================================
--- django/db/backends/mysql_old/creation.py	(revision 7053)
+++ django/db/backends/mysql_old/creation.py	(working copy)
@@ -16,6 +16,7 @@
     'ImageField':        'varchar(%(max_length)s)',
     'IntegerField':      'integer',
     'IPAddressField':    'char(15)',
+    'IP6AddressField':   'char(39)',
     'NullBooleanField':  'bool',
     'OneToOneField':     'integer',
     'PhoneNumberField':  'varchar(20)',
Index: django/db/backends/sqlite3/creation.py
===================================================================
--- django/db/backends/sqlite3/creation.py	(revision 7053)
+++ django/db/backends/sqlite3/creation.py	(working copy)
@@ -15,6 +15,7 @@
     'ImageField':                   'varchar(%(max_length)s)',
     'IntegerField':                 'integer',
     'IPAddressField':               'char(15)',
+    'IP6AddressField':              'char(39)',
     'NullBooleanField':             'bool',
     'OneToOneField':                'integer',
     'PhoneNumberField':             'varchar(20)',
Index: django/db/backends/mysql/creation.py
===================================================================
--- django/db/backends/mysql/creation.py	(revision 7053)
+++ django/db/backends/mysql/creation.py	(working copy)
@@ -16,6 +16,7 @@
     'ImageField':        'varchar(%(max_length)s)',
     'IntegerField':      'integer',
     'IPAddressField':    'char(15)',
+    'IPAddressField':    'char(39)',
     'NullBooleanField':  'bool',
     'OneToOneField':     'integer',
     'PhoneNumberField':  'varchar(20)',
Index: django/db/backends/oracle/creation.py
===================================================================
--- django/db/backends/oracle/creation.py	(revision 7053)
+++ django/db/backends/oracle/creation.py	(working copy)
@@ -19,6 +19,7 @@
     'ImageField':                   'NVARCHAR2(%(max_length)s)',
     'IntegerField':                 'NUMBER(11)',
     'IPAddressField':               'VARCHAR2(15)',
+    'IP6AddressField':              'VARCHAR2(39)',
     'NullBooleanField':             'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
     'OneToOneField':                'NUMBER(11)',
     'PhoneNumberField':             'VARCHAR2(20)',
Index: django/db/backends/postgresql_psycopg2/introspection.py
===================================================================
--- django/db/backends/postgresql_psycopg2/introspection.py	(revision 7053)
+++ django/db/backends/postgresql_psycopg2/introspection.py	(working copy)
@@ -72,7 +72,7 @@
     23: 'IntegerField',
     25: 'TextField',
     701: 'FloatField',
-    869: 'IPAddressField',
+    869: 'IP6AddressField',
     1043: 'CharField',
     1082: 'DateField',
     1083: 'TimeField',
Index: django/core/validators.py
===================================================================
--- django/core/validators.py	(revision 7053)
+++ django/core/validators.py	(working copy)
@@ -106,8 +106,15 @@
         except ValidationError:
             raise ValidationError, _("Enter valid e-mail addresses separated by commas.")
 
-def isValidIPAddress4(field_data, all_data):
+def isValidIP4Address(field_data, all_data):
     if not ip4_re.search(field_data):
+        raise ValidationError, _("Please enter a valid IPv4 address.")
+
+def isValidIPAddress(field_data, all_data):
+    import IPy
+    try:
+        IPy.parseAddress(field_data)
+    except ValueError:
         raise ValidationError, _("Please enter a valid IP address.")
 
 def isNotEmpty(field_data, all_data):
Index: django/newforms/fields.py
===================================================================
--- django/newforms/fields.py	(revision 7053)
+++ django/newforms/fields.py	(working copy)
@@ -16,6 +16,8 @@
 except NameError:
     from sets import Set as set
 
+import IPy
+
 from django.utils.translation import ugettext_lazy as _
 from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str
 
@@ -31,7 +33,7 @@
     'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
     'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
     'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
-    'SplitDateTimeField', 'IPAddressField',
+    'SplitDateTimeField', 'IPAddressField', 'IP6AddressField',
 )
 
 # These values, if given to to_python(), will trigger the self.required check.
@@ -754,3 +756,17 @@
 
     def __init__(self, *args, **kwargs):
         super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs)
+
+class IP6AddressField(CharField):
+    def __init__(self, *args, **kwargs):
+        super(IP6AddressField, self).__init__(39, 3, *args, **kwargs)
+
+    def clean(self, value):
+        value = super(IP6AddressField, self).clean(value)
+        if value == u'':
+            return value
+        try:
+            IPy.parseAddress(value)
+        except ValueError:
+            raise ValidationError(_(u'Enter a valid IP address.'))
+        return value
Index: tests/regressiontests/forms/extra.py
===================================================================
--- tests/regressiontests/forms/extra.py	(revision 7053)
+++ tests/regressiontests/forms/extra.py	(working copy)
@@ -310,6 +310,85 @@
 ...
 ValidationError: [u'Enter a valid IPv4 address.']
 
+# IP6AddressField ##################################################################
+
+>>> f = IP6AddressField()
+>>> 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.clean('127.0.0.1')
+u'127.0.0.1'
+>>> f.clean('2a01:05d8:25ae:9451:020d:39bc:21e6:8cab')
+u'2a01:05d8:25ae:9451:020d:39bc:21e6:8cab'
+>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:21e6:8cab')
+u'2a01:5d8:25ae:9451:20d:39bc:21e6:8cab'
+>>> f.clean('::1')
+u'::1'
+>>> f.clean('::ffff:88.191.32.1')
+u'::ffff:88.191.32.1'
+>>> f.clean('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('127.0.0.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('::1:')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('1.2.3.4.5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:21e6:8cab:fb2c')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 39 characters (it has 42).']
+>>> f.clean('2a01:5d8:25ae:9451:20d:39bc:1e6:cab:b2c')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('256.125.1.5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('::12345')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+
+>>> f = IP6AddressField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+>>> f.clean('127.0.0.1')
+u'127.0.0.1'
+>>> f.clean('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('127.0.0.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('1.2.3.4.5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+>>> f.clean('256.125.1.5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IP address.']
+
+
 #################################
 # Tests of underlying functions #
 #################################
Index: docs/newforms.txt
===================================================================
--- docs/newforms.txt	(revision 7053)
+++ docs/newforms.txt	(working copy)
@@ -1390,6 +1390,16 @@
       expression.
     * Error message keys: ``required``, ``invalid``
 
+``IP6AddressField``
+~~~~~~~~~~~~~~~~~~
+
+    * Default widget: ``TextInput``
+    * Empty value: ``''`` (an empty string)
+    * Normalizes to: A Unicode object.
+    * Validates that the given value is a valid IPv4 or IPv6 address, using
+      IPy
+    * Error message keys: ``required``, ``invalid``
+
 ``MultipleChoiceField``
 ~~~~~~~~~~~~~~~~~~~~~~~
 
Index: docs/model-api.txt
===================================================================
--- docs/model-api.txt	(revision 7053)
+++ docs/model-api.txt	(working copy)
@@ -388,6 +388,18 @@
 
 The admin represents this as an ``<input type="text">`` (a single-line input).
 
+``IP6AddressField``
+~~~~~~~~~~~~~~~~~~
+
+An IPv6 or IPv4 address, in string format (i.e. "24.124.1.30",
+"2002:58bf:278c::1", "::ffff:88.191.52.1").
+
+The admin represents this as an ``<input type="text">`` (a single-line input).
+
+Requires `IPy`_.
+
+.. _IPy: http://software.inl.fr//trac/wiki/IPy
+
 ``NullBooleanField``
 ~~~~~~~~~~~~~~~~~~~~
 
Index: docs/modelforms.txt
===================================================================
--- docs/modelforms.txt	(revision 7053)
+++ docs/modelforms.txt	(working copy)
@@ -58,6 +58,7 @@
     ``ImageField``                   ``ImageField``
     ``IntegerField``                 ``IntegerField``
     ``IPAddressField``               ``IPAddressField``
+    ``IP6AddressField``               ``IP6AddressField``
     ``ManyToManyField``              ``ModelMultipleChoiceField`` (see
                                      below)
     ``NullBooleanField``             ``CharField``
Index: docs/form_for_model.txt
===================================================================
--- docs/form_for_model.txt	(revision 7053)
+++ docs/form_for_model.txt	(working copy)
@@ -65,6 +65,7 @@
     ``ImageField``                   ``ImageField``
     ``IntegerField``                 ``IntegerField``
     ``IPAddressField``               ``IPAddressField``
+    ``IP6AddressField``               ``IP6AddressField``
     ``ManyToManyField``              ``ModelMultipleChoiceField`` (see
                                      below)
     ``NullBooleanField``             ``CharField``
