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

Thanks pmartin for the report.
This commit is contained in:
Tim Graham 2014-06-30 14:34:45 -04:00
parent 1966054feb
commit 7fd55c3481
10 changed files with 46 additions and 17 deletions

View File

@ -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),
),
]

View File

@ -124,7 +124,9 @@ class EmailValidator(object):
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)', # quoted-string r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)', # quoted-string
re.IGNORECASE) re.IGNORECASE)
domain_regex = re.compile( 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) re.IGNORECASE)
literal_regex = re.compile( literal_regex = re.compile(
# literal form, ipv4 or ipv6 address (SMTP 4.1.3) # literal form, ipv4 or ipv6 address (SMTP 4.1.3)

View File

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

View File

@ -535,18 +535,14 @@ The default form widget for this field is a :class:`~django.forms.TextInput`.
``EmailField`` ``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. 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 The default ``max_length`` was increased from 75 to 254 in order to be
possible RFC3696/5321-compliant email addresses. In order to store all compliant with RFC3696/5321.
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`.
``FileField`` ``FileField``
------------- -------------

View File

@ -373,6 +373,17 @@ lookups::
... ...
ValueError: Cannot query "<Book: Django>": Must be "Author" instance. 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 Miscellaneous
~~~~~~~~~~~~~ ~~~~~~~~~~~~~

View File

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

View File

@ -54,7 +54,7 @@ class InspectDBTestCase(TestCase):
assertFieldType('date_time_field', "models.DateTimeField()") assertFieldType('date_time_field', "models.DateTimeField()")
if (connection.features.can_introspect_max_length and if (connection.features.can_introspect_max_length and
not connection.features.interprets_empty_strings_as_nulls): 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_field', "models.CharField(max_length=100)")
assertFieldType('file_path_field', "models.CharField(max_length=100)") assertFieldType('file_path_field', "models.CharField(max_length=100)")
if connection.features.can_introspect_ip_address_field: if connection.features.can_introspect_ip_address_field:

View File

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

View File

@ -11,7 +11,7 @@ class MaxLengthArgumentsTests(unittest.TestCase):
self.assertEqual(model._meta.get_field(field).max_length, length) self.assertEqual(model._meta.get_field(field).max_length, length)
def test_default_max_lengths(self): 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, 'vcard', 100)
self.verify_max_length(PersonWithDefaultMaxLengths, 'homepage', 200) self.verify_max_length(PersonWithDefaultMaxLengths, 'homepage', 200)
self.verify_max_length(PersonWithDefaultMaxLengths, 'avatar', 100) self.verify_max_length(PersonWithDefaultMaxLengths, 'avatar', 100)

View File

@ -66,6 +66,9 @@ TEST_DATA = (
(validate_email, '"\\\011"@here.com', None), (validate_email, '"\\\011"@here.com', None),
(validate_email, '"\\\012"@here.com', ValidationError), (validate_email, '"\\\012"@here.com', ValidationError),
(validate_email, 'trailingdot@shouldfail.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, 'slug-ok', None),
(validate_slug, 'longer-slug-still-ok', None), (validate_slug, 'longer-slug-still-ok', None),