[Django] #28176: Expose real (i.e. not converted to string) value in widget option context

9 views
Skip to first unread message

Django

unread,
May 5, 2017, 12:18:31 PM5/5/17
to django-...@googlegroups.com
#28176: Expose real (i.e. not converted to string) value in widget option context
------------------------------------------+------------------------
Reporter: Moritz Sichert | Owner: nobody
Type: New feature | Status: new
Component: Forms | Version: master
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
------------------------------------------+------------------------
In #28075 `option.value` was changed to always be converted to a string
before passing it to the template. I have a use case that doesn't work
anymore because of this. I have this form:

{{{#!python
from django.forms import Form, RadioSelect, TypedChoiceField


CHOICES = [
(1, 'INFO'),
(2, 'WARNING'),
(3, 'SUCCESS'),
(4, 'DANGER'),
]

CHOICES_DICT = {name: value for value, name in CHOICES}


class RadioSelectWithIcons(RadioSelect):
template_name = 'radio_select_with_icons.html'

def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
context['choices'] = CHOICES_DICT
return context


class MyForm(Form):
foo = TypedChoiceField(
coerce=int,
choices=CHOICES,
widget=RadioSelectWithIcons
)
}}}

and the following template (`radio_select_with_icons.html`):

{{{#!htmldjango
{% for _, options, _ in widget.optgroups %}
{% for option in options %}
<label class="btn btn-default{% if option.selected %} active{% endif
%}">
<input type="radio" name="{{ widget.name }}" value="{{ option.value
}}"{% if option.selected %} checked="checked"{% endif %}>
{{ option.label }}
{% if option.value == choices.INFO %}
<span class="fa fa-info-circle text-info"></span>
{% elif option.value == choices.WARNING %}
<span class="fa fa-times-circle text-warning"></span>
{% elif option.value == choices.SUCCESS %}
<span class="fa fa-check-circle text-success"></span>
{% elif option.value == choices.DANGER %}
<span class="fa fa-exclamation-circle text-danger"></span>
{% endif %}
</label>
{% endfor %}
{% endfor %}
}}}
Now, when I render this form, none of the `<span class="fa ..."></span>`
are displayed. This is because `option.value` is a string and `choices.X`
are integers so the equality will obviously always be false.

I can see two solutions to this that don't involve changing code in
Django:

1.: Convert the integers in the `choices` to strings as well. I don't
think this is a sensible solution since I ''know'' that both values are
supposed to be integers but instead compare their string representations.
This also becomes a problem if the string version of the value is
ambiguous, e.g. translated strings.
2.: Pass the css classes I use in the `<span>` as context from the widget.
I also think, that this is a bad approach, because I want to separate
python code from display logic. This also wouldn't work for more complex
things that don't change just a css class.


I think there is a good, simple solution to this: In
`ChoiceWidget.create_option()` the returned context should also contain
the un-stringified value. Maybe even rename the current `value` to
`str_value` and store the actual value in `value`.

What do you think?

--
Ticket URL: <https://code.djangoproject.com/ticket/28176>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
May 5, 2017, 12:42:47 PM5/5/17
to django-...@googlegroups.com
#28176: Expose real (i.e. not converted to string) value in widget option context
--------------------------------+--------------------------------------

Reporter: Moritz Sichert | Owner: nobody
Type: New feature | Status: new
Component: Forms | Version: master
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------
Changes (by Tim Graham):

* cc: Preston Timmons (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/28176#comment:1>

Django

unread,
May 9, 2017, 12:28:22 PM5/9/17
to django-...@googlegroups.com
#28176: Expose real (i.e. not converted to string) value in widget option context
--------------------------------+------------------------------------

Reporter: Moritz Sichert | Owner: nobody
Type: New feature | Status: new
Component: Forms | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Changes (by Tim Graham):

* stage: Unreviewed => Accepted


--
Ticket URL: <https://code.djangoproject.com/ticket/28176#comment:2>

Django

unread,
May 9, 2017, 3:20:30 PM5/9/17
to django-...@googlegroups.com
#28176: Expose real (i.e. not converted to string) value in widget option context
--------------------------------+------------------------------------

Reporter: Moritz Sichert | Owner: nobody
Type: New feature | Status: new
Component: Forms | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------

Comment (by cg):

A third option to deal with this issue within the template itself would be
to use a django filter to convert the int into a string:

{{{#!htmldjango
{{ value|stringformat:"i" }}
}}}

For example:

{{{#!htmldjango
{% if option.value == choices.INFO|stringformat:"i" %}


<span class="fa fa-info-circle text-info"></span>

...
}}}

Relevant docs:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#stringformat\

It's definitely not ideal though.

--
Ticket URL: <https://code.djangoproject.com/ticket/28176#comment:3>

Django

unread,
Jun 15, 2017, 11:50:03 AM6/15/17
to django-...@googlegroups.com
#28176: Expose real (i.e. not converted to string) value in widget option context
--------------------------------+------------------------------------

Reporter: Moritz Sichert | Owner: nobody
Type: New feature | Status: new
Component: Forms | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Changes (by Tim Graham):

* has_patch: 0 => 1


Comment:

On the PR for #28303
[https://github.com/django/django/pull/8639#issuecomment-308612817 John
suggested], "If this lands, the option's input's value could be added to
the attrs dict in `Widget.create_option()`, then value could resume to be
the actual value, not the coerced value." I implemented that idea in the
second commit of a [https://github.com/django/django/pull/8646 PR], then
simplified things to what I think is a simpler approach in the third
commit.

--
Ticket URL: <https://code.djangoproject.com/ticket/28176#comment:4>

Django

unread,
Jun 17, 2017, 6:39:22 PM6/17/17
to django-...@googlegroups.com
#28176: Expose real (i.e. not converted to string) value in widget option context
--------------------------------+------------------------------------

Reporter: Moritz Sichert | Owner: nobody
Type: New feature | Status: closed
Component: Forms | Version: master
Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Changes (by Tim Graham <timograham@…>):

* status: new => closed
* resolution: => fixed


Comment:

In [changeset:"221e6e18177516ac4ac95e40c344b93d14dd607b" 221e6e1]:
{{{
#!CommitTicketReference repository=""
revision="221e6e18177516ac4ac95e40c344b93d14dd607b"
Fixed #28176 -- Restored the uncasted option value in ChoiceWidget
template context.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/28176#comment:5>

Django

unread,
Jun 17, 2017, 6:39:44 PM6/17/17
to django-...@googlegroups.com
#28176: Expose real (i.e. not converted to string) value in widget option context
--------------------------------+------------------------------------

Reporter: Moritz Sichert | Owner: nobody
Type: New feature | Status: closed
Component: Forms | Version: master

Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"a3b1319d5863600981e71fbaa452d7104715a9e7" a3b1319]:
{{{
#!CommitTicketReference repository=""
revision="a3b1319d5863600981e71fbaa452d7104715a9e7"
[1.11.x] Fixed #28176 -- Restored the uncasted option value in
ChoiceWidget template context.

Backport of 221e6e18177516ac4ac95e40c344b93d14dd607b from master
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/28176#comment:6>

Reply all
Reply to author
Forward
0 new messages