Proposal to add attribute 'step' to FloatField and DecimalField

353 views
Skip to first unread message

Jacob Rief

unread,
Mar 16, 2021, 7:45:26 PM3/16/21
to Django developers (Contributions to Django itself)
If someone wants to use the step attribute as provided by the HTML field
<input type="number" ...> , she/he has to specify that using for instance
FloatField(widget=NumberInput(attrs={'step': 0.5})).

Since the HTML standard offers a step attribute on input fields of type number,
from my point of view, this feature shall be reflected by Django's FloatField and 
optionally DecimalField rather than having to parametrize the widget.

Min- and max-values are already supported by the FloatField, so the step-value
would make sense here as well. It furthermore would require to revalidate the
step-value by Django's Form validation, rather than by HTML alone.

– Jacob

Markus Holtermann

unread,
Mar 16, 2021, 7:49:48 PM3/16/21
to Django developers
Hi Jacob,

That sounds like a sensible feature. Do you want to open a ticket and maybe implement it?

Cheers

Markus
> --
> You received this message because you are subscribed to the Google
> Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-develop...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/9a35aa63-0d22-4353-8f58-70a181e05791n%40googlegroups.com <https://groups.google.com/d/msgid/django-developers/9a35aa63-0d22-4353-8f58-70a181e05791n%40googlegroups.com?utm_medium=email&utm_source=footer>.

Jacob Rief

unread,
Mar 17, 2021, 3:54:29 AM3/17/21
to Django developers (Contributions to Django itself)
On Wednesday, March 17, 2021 at 12:49:48 AM UTC+1 in...@markusholtermann.eu wrote:
That sounds like a sensible feature. Do you want to open a ticket and maybe implement it?

Hi Markus,
ticket #32559 has been issued to propose this feature.
If accepted I will assign myself to implement it.

– Jacob

Josh Smeaton

unread,
Mar 17, 2021, 7:35:25 AM3/17/21
to Django developers (Contributions to Django itself)
Just to clarify - you're talking about form fields rather than model fields, right? I can see the argument for form fields but not for model fields.

Is there a better API we can think of for customising widgets from the field constructor that could then be passed through? As a rough example:

my_step_field = forms.FloatField(widget_attributes={"step": 0.5})

Rather than encode each kind of attribute in the form field constructor it could take a dictionary that is passed along to customise the widget. Often I've found it 
annoying to track down the exact widget required, find the import, and then customise the widget. The specific arguments to fill out the attributes are less onerous.

Thoughts?

Carlton Gibson

unread,
Mar 17, 2021, 9:08:52 AM3/17/21
to django-d...@googlegroups.com
Hiya, 

DecimalField already sets step based on the number of decimal places 

    def test_decimalfield_widget_attrs(self):
        f = DecimalField(max_digits=6, decimal_places=2)
        self.assertEqual(f.widget_attrs(Widget()), {})
        self.assertEqual(f.widget_attrs(NumberInput()), {'step': '0.01'})
        f = DecimalField(max_digits=10, decimal_places=0)
        self.assertEqual(f.widget_attrs(NumberInput()), {'step': '1'})
        f = DecimalField(max_digits=19, decimal_places=19)
        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, '<input step="0.01" name="f" type="number" id="id_f" required>')

I’m not sure about extending it for FloatField:

On 17 Mar 2021, at 12:35, Josh Smeaton <josh.s...@gmail.com> wrote:

Is there a better API we can think of for customising widgets from the field constructor that could then be passed through? As a rough example:

my_step_field = forms.FloatField(widget_attributes={"step": 0.5})

Thoughts?


In general, I think we should be very cautious about adding more API here. 

There’s already one clear way to do it, passing the widget. 

Adding (say) a widget_attributes is no clearer than the original: 

my_step_field = forms.FloatField(widget=NumberInput(attrs={'step': 0.5})).

Except now there are TWO ways of configuring one widget attribute. 

We set maxlength/minlength on widgets for CharFields because they map from an already existing kwarg

For the case of `step` on a FloatField we’d need to add a kwarg — but that’s only there to set a single attribute on the widget. 

In that case, I don’t think the explicit declaration is too much to ask. 

“But I need this for all my forms” — create a project-level field and declare it once there.

While not all attributes have custom kwargs on the field: 
"We can set THAT widget attribute from the field, why not THIS one?”

tl;dr: I sceptical this would be a good extension of the API surface area. 

C. 

Jacob Rief

unread,
Mar 17, 2021, 10:34:01 AM3/17/21
to Django developers (Contributions to Django itself)
We set maxlength/minlength on widgets for CharFields because they map from an already existing kwarg

For the case of `step` on a FloatField we’d need to add a kwarg — but that’s only there to set a single attribute on the widget. 

But FloatField also offers a min_value and max_value. When rendered as a widget, they are used as attributes min and max in their input
field. In addition to that, the field value is validated against a value in that range. To be consistent, the same should apply to the step value.
This would  furthermore allow the field to validate against a multiple of that step value. Such a feature currently has to be implemented on the project level.

I agree with Carlton that in the DecimalField this is handled by the attribute decimal_places.

– Jacob

Carlton Gibson

unread,
Mar 17, 2021, 10:44:11 AM3/17/21
to django-d...@googlegroups.com


On 17 Mar 2021, at 15:34, Jacob Rief <jacob...@gmail.com> wrote:

But FloatField also offers a min_value and max_value. When rendered as a widget, they are used as attributes min and max in their input
field. In addition to that, the field value is validated against a value in that range. To be consistent, the same should apply to the step value.
This would  furthermore allow the field to validate against a multiple of that step value. Such a feature currently has to be implemented on the project level.

If we’re happy to add that extra to forms.FloatField then it would alleviate my concern about a pass-through parameter. (At least the field would be **doing** something with it.) 

(I don’t object if everyone is keen.) 
C.


Adam Johnson

unread,
Mar 17, 2021, 10:51:13 AM3/17/21
to django-d...@googlegroups.com
I agree that it makes sense to add the argument to FloatField so we can add the server-side validation logic. I would also like to see it on IntegerField for consistency, and since IntegerField also maps to a NumberInput.

I'd also be against the widget_attributes proposal - there are already too many ways of configuring form fields/widgets, we don't need another.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.


--
Adam

Jacob Rief

unread,
Mar 17, 2021, 12:04:59 PM3/17/21
to Django developers (Contributions to Django itself)
Great News!
So please accept ticket #32559. I then will assign myself to it and implement it.
So I add step (or would you prefer step_value?) to IntegerField and FloatField, but not to DecimalField (because there it's handled through decimal_places).

Kapil Bansal

unread,
Mar 21, 2021, 4:53:43 PM3/21/21
to Django developers (Contributions to Django itself)
Hi everyone,
I am working on this and I have a question.
How to write validation check for this?
Due to python floating point issues, I am not able to validate whether field value is of given step_size or not

- Kapil

Jacob Rief

unread,
Mar 21, 2021, 7:47:35 PM3/21/21
to Django developers (Contributions to Django itself)
Say, you have a value and step, both are floats, then if value / step is can be represented
integer, the validation is fulfilled. Otherwise if the result has to be rounded to become an integer,
a ValidationError shall be raised.
Be aware of rounding errors.

Adam Johnson

unread,
Mar 22, 2021, 3:53:15 AM3/22/21
to django-d...@googlegroups.com

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.


--
Adam

Jacob Rief

unread,
Mar 22, 2021, 7:11:08 AM3/22/21
to Django developers (Contributions to Django itself)
The problem with modulo on floats is, that due to rounding errors it often created weird results,
for instance in Python-3.8 this happens: 3.5 % 0.1 = 0.09999999999999981
This btw. also applies to the builtin divmod and math.fmod functions.
Therefore I proposed to do it via classic division and check if it's near enough to an integer value.

James Bennett

unread,
Mar 22, 2021, 7:23:00 AM3/22/21
to django-d...@googlegroups.com
There are ways to check "close enough" equality for floats. There's
even the math.isclose() function which is arbitrarily tune-able:

https://docs.python.org/3/library/math.html#math.isclose

Kapil Bansal

unread,
Mar 22, 2021, 7:36:27 AM3/22/21
to django-d...@googlegroups.com
I do something similar to what math.isclose() provides. Can anyone please review this PR:-

--
You received this message because you are subscribed to a topic in the Google Groups "Django developers  (Contributions to Django itself)" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-developers/oVWKJUXTb1o/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAL13Cg9kom4X57gaUp%2Bq8%3DqdEF_33hTEZ9AMi8bucXjaKXsX8Q%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages