4

I'm trying to make a NumberInput widget that has steps of 0.5, which is defined in the form as the following:

widgets = {
    "hours_per_day": widgets.NumberInput(attrs={'step': '0.5'})
}

However, the template is always rendered with the attribute step being 0.1. This widget is for a ModelForm's DecimalField. Why is the step attribute not changing?

Here's the (useful) code from the form:

class Registration_form(ModelForm):
    class Meta:
        model = Registration

        fields = [
            "hours_per_day",
        ]

        widgets = {
            "hours_per_day": widgets.NumberInput(attrs={'step': '1'})
        }
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Seth Rubin
  • 43
  • 1
  • 4

2 Answers2

5

Try defining the NumberInput as a TextInput like so, and then step by 0.5:

from django.forms.widgets import TextInput

class NumberInput(TextInput):
    input_type = 'number'


#Usage
widgets = (
    'number_field': NumberInput(attrs={'min': '0', 'max': '10', 'step': '0.5'}),

)
Aaron Lelevier
  • 19,850
  • 11
  • 76
  • 111
  • 4
    Thanks, it worked! You actually don't have to make a new class for it, I just made the widget a `TextInput` and added the attribute `'type': 'number'`. – Seth Rubin Jul 14 '14 at 20:23
  • I cannot get your code to work. Your definition of widgets does not even parse. And if I try to fix that parse error, what I am left with doesn't seem to differ in any relevant way from the version in the question. Additionally your definition of class NumberInput is completely identical to django's own, so that could be left out without changing the behavior. – kasperd Nov 24 '14 at 16:53
  • I realized `1.` When testing your version with the syntax error corrected, I had mistakenly used the key `number_field` rather than the name of the field in my application. `2.` For some reason defining `NumberInput` locally does make a difference even if the definition is identical to the one within django. Why two identical class definitions make a difference is still a mystery. Without knowing the reason for that, I don't know if your solution is really the cleanest solution. – kasperd Nov 24 '14 at 17:18
  • 3
    Turns out django.form.fields.DecimalField.widget_attrs uses `isinstance` to explicitly check if the widget is `django.forms.widgets.NumberInput` and if that is the case, it does `attrs.setdefault('step', step)`. Why the `step` value from `DecimalField` overrides the one I specify is unclear to me. – kasperd Nov 24 '14 at 17:30
0

You can use forms.NumberInput() to override step attribute of forms.DecimalField() with these ways as shown below:

from django import forms

class TestForm(forms.ModelForm):
    class Meta:
        widgets = {
            'num': forms.NumberInput(attrs={'step': 0.5})
        }          # Here
from django import forms

class TestForm(forms.ModelForm):
    num = forms.DecimalField(
        widget=forms.NumberInput(attrs={'step': 0.5})
    )          # Here
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129