#28316: ModelChoiceField with to_field_name fails to render a widget properly
--------------------------------+--------------------------------------
Reporter: László Károlyi | Owner: nobody
Type: Bug | 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
--------------------------------+--------------------------------------
Comment (by László Károlyi):
So I guess I just opened a huge can of worms. In a nutshell:
ModelForm ForeignKey data is initialized on ModelForms at `__init__` time,
and then, only the PKs are put into the `self.initial` dict. Hence, the
time the `BoundField` wants to pass it over to
`ModelChoiceField.prepare_value()`, it only has the PK.
There are two 'workarounds', neither of which is good looking, but fixes
the problem:
1: Patch `ModelChoiceField.prepare_value()`:
{{{#!python
def prepare_value(self, value):
if hasattr(value, '_meta'):
if self.to_field_name:
return value.serializable_value(self.to_field_name)
else:
return value.pk
if self.to_field_name:
# Case for lookup when only a PK is passed
selected_value = [x for x in self.queryset if x.pk == value]
if selected_value:
return getattr(selected_value[0], self.to_field_name)
return super().prepare_value(value)
}}}
2: Patch `BoundField.value()`:
{{{#!python
def value(self):
"""
Return the value for this BoundField, using the initial value if
the form is not bound or the data otherwise.
"""
from django.forms.models import ModelChoiceField
data = self.initial
if self.form.is_bound:
data = self.field.bound_data(self.data, data)
elif hasattr(self.form, 'instance') and self.form.instance.pk and
type(self.field) is ModelChoiceField:
# First display: form non-bound but has an existing
# instance, override any initials
data = getattr(self.form.instance, self.name)
return self.field.prepare_value(data)
}}}
I got a test, the whole test suite runs with both patches, posted in a
pull request (the first version is commented out but it's there):
https://github.com/django/django/pull/8650
This part of Django with the forms seems to be seriously not well thought
out, to put it mildly.
Any suggestions are welcome, I spent ~8 hrs pondering on the solution, and
traversing the Django source.
--
Ticket URL: <https://code.djangoproject.com/ticket/28316#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/065.886f4098638b40e8b30b0285c56d3771%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.