Browse Source

Fixed #20631 -- Increased the default EmailField max_length to 254.

Thanks pmartin for the report.
Tim Graham 10 years ago
parent
commit
7fd55c3481

+ 19 - 0
django/contrib/auth/migrations/0003_alter_user_email_max_length.py

@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('auth', '0002_alter_permission_name_max_length'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='user',
+            name='email',
+            field=models.EmailField(max_length=254, verbose_name='email address', blank=True),
+        ),
+    ]

+ 3 - 1
django/core/validators.py

@@ -124,7 +124,9 @@ class EmailValidator(object):
         r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)',  # quoted-string
         re.IGNORECASE)
     domain_regex = re.compile(
-        r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,}(?<!-))$',
+        # max length of the domain is 251: 254 (max email length) minus one
+        # period and two characters for the TLD.
+        r'(?:[A-Z0-9](?:[A-Z0-9-]{0,249}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,}(?<!-))$',
         re.IGNORECASE)
     literal_regex = re.compile(
         # literal form, ipv4 or ipv6 address (SMTP 4.1.3)

+ 2 - 4
django/db/models/fields/__init__.py

@@ -1567,10 +1567,8 @@ class EmailField(CharField):
     description = _("Email address")
 
     def __init__(self, *args, **kwargs):
-        # max_length should be overridden to 254 characters to be fully
-        # compliant with RFCs 3696 and 5321
-
-        kwargs['max_length'] = kwargs.get('max_length', 75)
+        # max_length=254 to be compliant with RFCs 3696 and 5321
+        kwargs['max_length'] = kwargs.get('max_length', 254)
         super(EmailField, self).__init__(*args, **kwargs)
 
     def deconstruct(self):

+ 4 - 8
docs/ref/models/fields.txt

@@ -535,18 +535,14 @@ The default form widget for this field is a :class:`~django.forms.TextInput`.
 ``EmailField``
 --------------
 
-.. class:: EmailField([max_length=75, **options])
+.. class:: EmailField([max_length=254, **options])
 
 A :class:`CharField` that checks that the value is a valid email address.
 
-.. admonition:: Incompliance to RFCs
+.. versionchanged:: 1.8
 
-    The default 75 character ``max_length`` is not capable of storing all
-    possible RFC3696/5321-compliant email addresses. In order to store all
-    possible valid email addresses, a ``max_length`` of 254 is required.
-    The default ``max_length`` of 75 exists for historical reasons. The
-    default has not been changed in order to maintain backwards
-    compatibility with existing uses of :class:`EmailField`.
+    The default ``max_length`` was increased from 75 to 254 in order to be
+    compliant with RFC3696/5321.
 
 ``FileField``
 -------------

+ 11 - 0
docs/releases/1.8.txt

@@ -373,6 +373,17 @@ lookups::
     ...
     ValueError: Cannot query "<Book: Django>": Must be "Author" instance.
 
+Default ``EmailField.max_length`` increased to 254
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The old default 75 character ``max_length`` was not capable of storing all
+possible RFC3696/5321-compliant email addresses. In order to store all
+possible valid email addresses, the ``max_length`` has been increased to 254
+characters. You will need to generate and apply database migrations for your
+affected models (or add ``max_length=75`` if you wish to keep the length on
+your current fields). A migration for
+:attr:`django.contrib.auth.models.User.email` is included.
+
 Miscellaneous
 ~~~~~~~~~~~~~
 

+ 1 - 1
tests/field_deconstruction/tests.py

@@ -128,7 +128,7 @@ class FieldDeconstructionTests(TestCase):
         name, path, args, kwargs = field.deconstruct()
         self.assertEqual(path, "django.db.models.EmailField")
         self.assertEqual(args, [])
-        self.assertEqual(kwargs, {"max_length": 75})
+        self.assertEqual(kwargs, {"max_length": 254})
         field = models.EmailField(max_length=255)
         name, path, args, kwargs = field.deconstruct()
         self.assertEqual(path, "django.db.models.EmailField")

+ 1 - 1
tests/inspectdb/tests.py

@@ -54,7 +54,7 @@ class InspectDBTestCase(TestCase):
         assertFieldType('date_time_field', "models.DateTimeField()")
         if (connection.features.can_introspect_max_length and
                 not connection.features.interprets_empty_strings_as_nulls):
-            assertFieldType('email_field', "models.CharField(max_length=75)")
+            assertFieldType('email_field', "models.CharField(max_length=254)")
             assertFieldType('file_field', "models.CharField(max_length=100)")
             assertFieldType('file_path_field', "models.CharField(max_length=100)")
         if connection.features.can_introspect_ip_address_field:

+ 1 - 1
tests/introspection/tests.py

@@ -70,7 +70,7 @@ class IntrospectionTests(TestCase):
             desc = connection.introspection.get_table_description(cursor, Reporter._meta.db_table)
         self.assertEqual(
             [r[3] for r in desc if datatype(r[1], r) == 'CharField'],
-            [30, 30, 75]
+            [30, 30, 254]
         )
 
     @skipUnlessDBFeature('can_introspect_null')

+ 1 - 1
tests/max_lengths/tests.py

@@ -11,7 +11,7 @@ class MaxLengthArgumentsTests(unittest.TestCase):
         self.assertEqual(model._meta.get_field(field).max_length, length)
 
     def test_default_max_lengths(self):
-        self.verify_max_length(PersonWithDefaultMaxLengths, 'email', 75)
+        self.verify_max_length(PersonWithDefaultMaxLengths, 'email', 254)
         self.verify_max_length(PersonWithDefaultMaxLengths, 'vcard', 100)
         self.verify_max_length(PersonWithDefaultMaxLengths, 'homepage', 200)
         self.verify_max_length(PersonWithDefaultMaxLengths, 'avatar', 100)

+ 3 - 0
tests/validators/tests.py

@@ -66,6 +66,9 @@ TEST_DATA = (
     (validate_email, '"\\\011"@here.com', None),
     (validate_email, '"\\\012"@here.com', ValidationError),
     (validate_email, 'trailingdot@shouldfail.com.', ValidationError),
+    # Max length of domain name in email is 251 (see validator for calculation)
+    (validate_email, 'a@%s.com' % ('a' * 251), None),
+    (validate_email, 'a@%s.com' % ('a' * 252), ValidationError),
 
     (validate_slug, 'slug-ok', None),
     (validate_slug, 'longer-slug-still-ok', None),