diff --git a/django/forms/fields.py b/django/forms/fields.py
index 3176ce65fa..100264247a 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -289,7 +289,7 @@ class FloatField(IntegerField):
def widget_attrs(self, widget):
attrs = super(FloatField, self).widget_attrs(widget)
- if isinstance(widget, NumberInput):
+ if isinstance(widget, NumberInput) and 'step' not in widget.attrs:
attrs.setdefault('step', 'any')
return attrs
@@ -377,7 +377,7 @@ class DecimalField(IntegerField):
def widget_attrs(self, widget):
attrs = super(DecimalField, self).widget_attrs(widget)
- if isinstance(widget, NumberInput):
+ if isinstance(widget, NumberInput) and 'step' not in widget.attrs:
if self.decimal_places is not None:
# Use exponential notation for small values since they might
# be parsed as 0 otherwise. ref #20765
diff --git a/tests/forms_tests/tests/test_fields.py b/tests/forms_tests/tests/test_fields.py
index fe11370bde..78b74aee4e 100644
--- a/tests/forms_tests/tests/test_fields.py
+++ b/tests/forms_tests/tests/test_fields.py
@@ -282,6 +282,10 @@ class FieldsTests(SimpleTestCase):
self.assertEqual(f.max_value, 1.5)
self.assertEqual(f.min_value, 0.5)
+ def test_floatfield_widget_attrs(self):
+ f = FloatField(widget=NumberInput(attrs={'step': 0.01, 'max': 1.0, 'min': 0.0}))
+ self.assertWidgetRendersTo(f, '')
+
def test_floatfield_localized(self):
"""
Make sure localized FloatField's widget renders to a text input with
@@ -392,6 +396,8 @@ class FieldsTests(SimpleTestCase):
self.assertEqual(f.widget_attrs(NumberInput()), {'step': '1e-19'})
f = DecimalField(max_digits=20)
self.assertEqual(f.widget_attrs(NumberInput()), {'step': 'any'})
+ f = DecimalField(max_digits=6, widget=NumberInput(attrs={'step': '0.01'}))
+ self.assertWidgetRendersTo(f, '')
def test_decimalfield_localized(self):
"""