diff --git a/django/forms/fields.py b/django/forms/fields.py
index c6704883a3..9af85c86e3 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -235,7 +235,10 @@ class CharField(Field):
attrs = super(CharField, self).widget_attrs(widget)
if self.max_length is not None:
# The HTML attribute is maxlength, not max_length.
- attrs.update({'maxlength': str(self.max_length)})
+ attrs['maxlength'] = str(self.max_length)
+ if self.min_length is not None:
+ # The HTML attribute is minlength, not min_length.
+ attrs['minlength'] = str(self.min_length)
return attrs
diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt
index aed1ab7c83..c2d34c5992 100644
--- a/docs/releases/1.10.txt
+++ b/docs/releases/1.10.txt
@@ -256,6 +256,9 @@ Forms
* Form and widget ``Media`` is now served using
:mod:`django.contrib.staticfiles` if installed.
+* The ```` tag rendered by :class:`~django.forms.CharField` now includes
+ a ``minlength`` attribute if the field has a ``min_length``.
+
Generic Views
~~~~~~~~~~~~~
diff --git a/tests/forms_tests/field_tests/test_charfield.py b/tests/forms_tests/field_tests/test_charfield.py
index 82f2035ea5..0927370af3 100644
--- a/tests/forms_tests/field_tests/test_charfield.py
+++ b/tests/forms_tests/field_tests/test_charfield.py
@@ -81,17 +81,30 @@ class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
"""
CharField.widget_attrs() always returns a dictionary (#15912).
"""
- # Return an empty dictionary if max_length is None
+ # Return an empty dictionary if max_length and min_length are both None.
f = CharField()
self.assertEqual(f.widget_attrs(TextInput()), {})
self.assertEqual(f.widget_attrs(Textarea()), {})
- # Otherwise, return a maxlength attribute equal to max_length
+ # Return a maxlength attribute equal to max_length.
f = CharField(max_length=10)
self.assertEqual(f.widget_attrs(TextInput()), {'maxlength': '10'})
self.assertEqual(f.widget_attrs(PasswordInput()), {'maxlength': '10'})
self.assertEqual(f.widget_attrs(Textarea()), {'maxlength': '10'})
+ # Return a minlength attribute equal to min_length.
+ f = CharField(min_length=5)
+ self.assertEqual(f.widget_attrs(TextInput()), {'minlength': '5'})
+ self.assertEqual(f.widget_attrs(PasswordInput()), {'minlength': '5'})
+ self.assertEqual(f.widget_attrs(Textarea()), {'minlength': '5'})
+
+ # Return both maxlength and minlength when both max_length and
+ # min_length are set.
+ f = CharField(max_length=10, min_length=5)
+ self.assertEqual(f.widget_attrs(TextInput()), {'maxlength': '10', 'minlength': '5'})
+ self.assertEqual(f.widget_attrs(PasswordInput()), {'maxlength': '10', 'minlength': '5'})
+ self.assertEqual(f.widget_attrs(Textarea()), {'maxlength': '10', 'minlength': '5'})
+
def test_charfield_strip(self):
"""
Values have whitespace stripped but not if strip=False.
diff --git a/tests/forms_tests/field_tests/test_emailfield.py b/tests/forms_tests/field_tests/test_emailfield.py
index 98c317a9ee..d9fe64d3bb 100644
--- a/tests/forms_tests/field_tests/test_emailfield.py
+++ b/tests/forms_tests/field_tests/test_emailfield.py
@@ -42,7 +42,7 @@ class EmailFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
def test_emailfield_min_max_length(self):
f = EmailField(min_length=10, max_length=15)
- self.assertWidgetRendersTo(f, '')
+ self.assertWidgetRendersTo(f, '')
with self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 10 characters (it has 9).'"):
f.clean('a@foo.com')
self.assertEqual('alf@foo.com', f.clean('alf@foo.com'))
diff --git a/tests/forms_tests/field_tests/test_urlfield.py b/tests/forms_tests/field_tests/test_urlfield.py
index 48e4a39328..0ad1bb65f9 100644
--- a/tests/forms_tests/field_tests/test_urlfield.py
+++ b/tests/forms_tests/field_tests/test_urlfield.py
@@ -91,7 +91,7 @@ class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
def test_urlfield_5(self):
f = URLField(min_length=15, max_length=20)
- self.assertWidgetRendersTo(f, '')
+ self.assertWidgetRendersTo(f, '')
with self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 15 characters (it has 12).'"):
f.clean('http://f.com')
self.assertEqual('http://example.com', f.clean('http://example.com'))