Here is the code to reproduce it:
{{{
from django.db import models
class MyTestModel(models.Model):
foo = models.NullBooleanField(blank=True, null=True)
}}}
{{{
from django import forms
class MyTestModelForm(forms.ModelForm):
class Meta:
model = MyTestModel
fields = ('foo',)
widgets = {
'foo': forms.RadioSelect,
}
}}}
I'm not sure if this is a bug or if the bahaviour is intentional.
As a workaround I tried to just initialize the choices manually in the
widget, like this:
{{{
widgets = {
'foo': forms.RadioSelect(choices=(('', 'Unknown'), ('1',
'Yes'), ('0', 'No'))),
}
}}}
However, this works in terms of storing the correct value, but it does not
render the selected radio input as checked.
I'd like to work in this if someone can confirm that this behaviour is not
intended.
--
Ticket URL: <https://code.djangoproject.com/ticket/27445>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Comment (by Takis Issaris):
Hi,
I can confirm that specifying the widget removes all input/select tags:
{{{
from app27445.forms import MyTestModelForm
str(MyTestModelForm())
<tr><th><label for="id_foo">Foo:</label></th><td><select id="id_foo"
name="foo">\n<option value="1" selected>Unknown</option>\n<option
value="2">Yes</option>\n<option value="3">No</option>\n</select></td></tr>
}}}
{{{
from app27445.forms import MyTestModelForm
str(MyTestModelForm())
<tr><th><label for="id_foo_0">Foo:</label></th><td><ul
id="id_foo"></ul></td></tr>
}}}
But I do not think this is specific to NullBooleanField as I get the same
output when using the BooleanField.
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:1>
* status: new => assigned
* owner: nobody => Kenneth Veldman
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:2>
* stage: Unreviewed => Accepted
Comment:
Was able to reproduce using the same model and forms. I added a couple of
more checks by using multiple fields like so:
{{{
class MyTestModel(models.Model):
foo = models.NullBooleanField(blank=True, null=True)
bar = models.BooleanField(blank=True)
baz = models.BooleanField()
bor = models.NullBooleanField()
}}}
All results in an empty form when using the {{{forms.RadioSelect}}}
widget.
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:3>
* owner: Kenneth Veldman => Jacob Rief
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:4>
Comment (by Tim Graham):
Not sure how much effort the fix is here, but for what it's worth, there's
a proposal that might involve deprecating `NullBooleanField` (#23130).
Completing that ticket might be more fruitful in the long run.
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:5>
Comment (by Takis Issaris):
After digging through the code for quite some time, I decided to cheat a
little and have another go at search StackOverflow.
This is what I found regarding the saved value not being reflected in the
rendered form (in an UpdateView for example).
It was suggested [http://stackoverflow.com/a/28262878] that one should use
the following choices to make it work:
{{{
choices=((None, 'N/A'), (True, 'Yes'), (False, 'No'))
}}}
That works for me for True and False, but not for the None value of the
NullBooleanField.
On the same thread a user named 'x0nix' suggests this snippet
[http://stackoverflow.com/a/28906939]:
{{{
class NullBooleanRadioSelect(RadioSelect):
def __init__(self, *args, **kwargs):
choices = (
(None, ugettext_lazy('Unknown')),
(True, ugettext_lazy('Yes')),
(False, ugettext_lazy('No'))
)
super(NullBooleanRadioSelect, self).__init__(choices=choices,
*args, **kwargs)
_empty_value = None
}}}
{{{
...
widgets = {'foo': NullBooleanRadioSelect()}
}}}
With this snippet all three values seem to be rendered correctly.
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:6>
Comment (by Takis Issaris):
After looking at the empty_value in the forms.widgets.RadioSelect, I tried
using the following for choices:
{{{
choices = (('', 'Unknown'), (True, 'Yes'), (False, 'No'))
}}}
With this the issue of the HTML rendering not selecting the saved value is
gone, so please ignore my previous post...
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:7>
Comment (by Takis Issaris):
Should the need for specifying the choices field as mentioned above be
documented?
Or should the behaviour be modified so that the default choices field is
set as in the previous post automatically?
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:8>
Comment (by Jacob Rief):
While #23130 "BooleanField should not override 'blank' if choices are
specified", might make sense on the long term, this report describes a
real bug.
I spoke with various people on the sprints, which had their concerns about
fixing #23130, so even if at any time ``NullBooleanField`` is removed, it
does not harm to fix this ticket.
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:9>
* needs_better_patch: 0 => 1
* has_patch: 0 => 1
Comment:
Repeating my comment from the [https://github.com/django/django/pull/7526
PR], we're targeting template-based widget rendering (#15667) for 1.11
which conflicts with this patch because things like `RendererMixin` are
removed. I think the widget would just need to be tweaked based on the
changes in that branch, but I want to look at ticket #23130 to see if that
idea might obsolete this fix so that we don't have to add a widget only to
deprecated it later.
I wonder if a documentation suggestion of how to make things work without
this widget could suffice for now, which would also help users of older
Django versions.
Also, it would be nice if you could summarize the concerns about fixing
#23130 that you discussed at the sprint.
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:10>
* owner: Jacob Rief => David Smith
* needs_better_patch: 1 => 0
Comment:
[https://github.com/django/django/pull/12946 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:11>
* needs_better_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:12>
* needs_better_patch: 1 => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:13>
* type: New feature => Cleanup/optimization
* component: Forms => Documentation
* stage: Accepted => Ready for checkin
Comment:
We're going to resolve this documenting providing widget choices
explicitly.
[https://github.com/django/django/pull/13437#pullrequestreview-504593718
PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:14>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"82bdc51e7afde3f17572f9c8e6fa805a692cd594" 82bdc51]:
{{{
#!CommitTicketReference repository=""
revision="82bdc51e7afde3f17572f9c8e6fa805a692cd594"
[3.1.x] Fixed #23681, Fixed #27445 -- Doc'd setting choices for
NullBooleanField widgets.
Thanks to David Smith for investigation and review.
Co-authored-by: Carlton Gibson <carlton...@noumenal.es>
Backport of d976c254fc76e5f04d81dfd9d142c58e933c9c92 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27445#comment:16>