Reputation: 126
I developed a Django application in which i have a form with some fields. Depending on the input additional fields are displayed are hidden. Now everything worked quit fine in Django 3.2.14 since the update in Django 4.0.6 it didn't worked anymore.
I first build a form, where if a "field_rule_display" exists the field widget is set as "HiddenInput".
class AnalysisForm(forms.Form):
def __init__(self, analysis_form_template: AnalysisFormTemplate, disable_required: bool, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout()
self.helper.add_input(Submit("submit", _("Evaluate"), css_class="btn-primary btn-lg"))
analysis_field_queryset = analysis_form_template.analysis_fields
analysis_form_url = reverse("analysis_form", args=(analysis_form_template.id,))
for field in analysis_field_queryset.all():
htmx_dictionary = _htmx_dictionary(analysis_form_url, field)
self.fields[field.name_for_formula] = _get_field_by_type(
field, htmx_dictionary, analysis_form_template, self.data
)
self.fields[field.name_for_formula].empty_values = empty_values()
self.helper.layout.fields.append(
Div(Field(field.name_for_formula), css_class=AnalysisFieldKind(field.kind).name)
)
if field.field_rule_display is not None and disable_required is False:
self.fields[field.name_for_formula].widget = forms.HiddenInput()
self.fields[field.name_for_formula].widget.attrs["disabled"] = True
if disable_required:
self.fields[field.name_for_formula].required = False
After the user enters a specific input into the form, htmx will send a request and i rebuild the form with the new fields. And here the problem starts, even if i update my field in the "self.fields" Django does not render the update and my form field is still hidden.
if field.field_rule_display is not None:
evaluated_result_display = self._evaluated_formula(
field,
analysis_form_template,
field.field_rule_display,
field.field_rule_display.formula,
cleaned_data,
)
if evaluated_result_display:
field_type = _get_field_by_type(
field, htmx_dictionary, analysis_form_template, cleaned_data
)
self.fields[field.name_for_formula] = field_type
self.fields[field.name_for_formula].initial = cleaned_data[field.name_for_formula]
Here the second field should be displayed, but only my border is shown as a result of changing the crispy layout helper.
if (
field.field_rule_display is None or (field.field_rule_display is not None and evaluated_result_display)
) and field.field_rule_highlight is not None:
evaluated_result_highlight = self._evaluated_formula(
field.name_for_formula,
analysis_form_template,
field.field_rule_highlight,
field.field_rule_highlight.formula,
cleaned_data,
)
if evaluated_result_highlight:
field_layout = Div(
Field(field.name_for_formula),
css_class=f"{AnalysisFieldKind(field.kind).name} border border-primary mb-2 p-2",
)
self.fields[field.name_for_formula].empty_values = empty_values()
field_layout_list.append(field_layout)
self.helper.layout.fields = field_layout_list
I would appreciate some help, why this does not work anymore in Django 4 but in Django 3 it worked without a problem.
Upvotes: 2
Views: 627
Reputation: 126
After some debugging i found a possible solution to my problem.
It seems that Django caches my form fields and their widgets in "_bound_fields_cache". Now there my fields widget is still set to "HiddenInput", even after updating the widget to a "TextInput".
So i tried updating the field in "_bound_fields_cache" and to my suprise it worked.
if field.field_rule_display is not None:
evaluated_result_display = self._evaluated_formula(
field,
analysis_form_template,
field.field_rule_display,
field.field_rule_display.formula,
cleaned_data,
)
if evaluated_result_display:
field_type = _get_field_by_type(
field, htmx_dictionary, analysis_form_template, cleaned_data
)
self.fields[field.name_for_formula] = field_type
self.fields[field.name_for_formula].initial = cleaned_data[field.name_for_formula]
if field.name_for_formula in self._bound_fields_cache:
self._bound_fields_cache[field.name_for_formula].field = field_type
But i am not quite satisfied with this kind of solution. I can't really point my finger why Django doesn't change the "_bound_fields_cache" after updating my form fields. Changing the "_bound_fields_cache" seems for me like an ugly hack... Is there perhaps a better solution?
Upvotes: 1