Django 4 динамическое обновление полей формы с помощью HTMX
Я разработал Django приложение, в котором у меня есть форма с некоторыми полями. В зависимости от ввода дополнительные поля отображаются или скрываются. Сейчас в Django 3.2.14 все работало нормально, после обновления в Django 4.0.6 перестало работать.
Сначала я создаю форму, где если существует "field_rule_display", виджет поля устанавливается как "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
После того, как пользователь введет в форму определенные данные, htmx отправит запрос, и я перестрою форму с новыми полями. И здесь начинается проблема, даже если я обновляю свое поле в "self.fields" Django не отображает обновление и поле моей формы остается скрытым.
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]
Здесь должно отображаться второе поле, но в результате изменения помощника crispy layout отображается только моя граница.
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
Буду признателен за помощь, почему это больше не работает в Django 4, а в Django 3 работало без проблем.
Большое спасибо.
После некоторой отладки я нашел возможное решение моей проблемы.
Похоже, что Django кэширует поля моей формы и их виджеты в "_bound_fields_cache". Теперь там виджет моих полей все еще имеет значение "HiddenInput", даже после обновления виджета на "TextInput".
Поэтому я попробовал обновить поле в "_bound_fields_cache" и, к моему удивлению, оно сработало.
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
Но я не совсем удовлетворен таким решением. Я не могу точно сказать, почему Django не изменяет "_bound_fields_cache" после обновления полей формы. Изменение "_bound_fields_cache" кажется мне уродливым хаком... Возможно, есть лучшее решение?