Django templatetag для доступа к произвольному полю формы, определенному аргументом

Этот конкретный блок кода повторяется около ста миллионов раз, только с разными полями формы, и поэтому я хочу заменить все эти строки на templatetags:

<label for="{{ form.building_name.id_for_label }}">Building</label>
<input name="{{ form.building_name.name }}" value="{{ form.instance.building_name }}">

Так что вместо того, чтобы написать это:

<label for="{{ form.building_name.id_for_label }}">
    <!-- plus many more lines just for this one element -->
<label for="{{ form.building_title.id_for_label }}">
    <!-- plus many more lines just for this one element -->
...

Я хочу написать следующее:

{% someTag 'building_name' %}
{% someTag 'building_title' %}

После долгих раздумий я пришел к одному из самых уродливых способов написания inclusion tag, на которые я когда-либо имел несчастье смотреть. Запутанная природа доступа к field объясняется тем, что я не нашел другого способа доступа к произвольному полю form.

Тег:

@register.inclusion_tag("main/sff.html")
def sff(form, field_name, label):
    field = form._meta.model._meta.get_field(field_name)
    return {'form': form, 'field': field, 'label' : label, 'ph' : placeholder}

sff.html:

<label for="{{ field.id_for_label }}">{{ label }}</label>
<input type="text" \
    name="{{ field.name }}" \
    value="{{ form.instance.field }}">
</div>

После всего сказанного и сделанного, вот как я вызываю его из моего HTML шаблона:

{% sff form 'building_name' 'Enter property name' %}

Консоль браузера показывает, что поле содержит name=building_name, но value пустое.

Я проверил в базе данных, что форма может успешно ПОСТАВИТЬ значения, поэтому часть name предположительно в порядке. Это самая важная часть, так что я почти достиг своей цели.

Но я никак не могу понять, как получить доступ к form.instance.<arbitrary_field> в templatetag. Я использую это для отображения существующего значения, которое имеет объект, и я использую этот подход вместо того, чтобы обращаться к нему через форму напрямую (как field.value), потому что, похоже, бывают случаи, когда форма либо очищается, либо по другим причинам больше не содержит значения базы данных.

Мне кажется, что этот ответ находится где-то в области обходных путей/хаков, поэтому я с радостью приму любой ответ, который будет более элегантным, более каноничным или вообще менее грязным, чем этот.

Я не могу найти простой или чистый способ разрешения утверждений типа {{ form.arbitrary_field_name }}, потому что я не знаю точно, почему, но похоже, что это как-то связано с полевыми объектами(?)

Однако существует способ получить доступ к значению поля экземпляра формы, передавая строковые аргументы - но только если мы используем ModelForm. Это не требует очень глубоких знаний Python, и опытные пользователи могут даже считать это довольно элементарным, но мне потребовались часы, чтобы подумать, чтобы рассмотреть это на концептуальном уровне.

ModelForm будут иметь экземпляр соответствующей модели, связанной с ними, а модель для целей этого поста идентична классу. А классы имеют __dict__().

Simple templatetags также обеспечивает новый способ доступа к полям form (работает с любым видом формы, насколько я знаю), где вы можете работать с ними на знакомом Python вместо колдовства Django-Jinja2-HTML.

Вооружившись этими знаниями - поскольку я использую ModelForm - вот как может выглядеть окончательный код:

@register.inclusion_tag("main/sff.html")
def sff(form, field_name, label):
    v = form.instance.__dict__[field]
    l = get_field_id_for_label(form, field)
    f = get_field_name(form, field)
    return {'form': form, 'field_name' : f, 'label' : label, 'value' : v, 'label_id' : l}

@register.simple_tag
def get_field_name(form, field_name):
    return form[field_name].name

@register.simple_tag
def get_field_id_for_label(form, field_name):
    return form[field_name].id_for_label

А теперь, в main/sff.html:

<label for="{{ label_id }}">{{ label }}</label>
<input type="text" \
    name="{{ field_name }}" \
    value="{{ value }}">

И вуаля, шаблонизатор теперь принимает этот ввод в шаблоне:

{% sff form 'building_name' 'Building' %}

и отображает его в таком виде для браузера:

    <label for="id_building_name">Building</label>
    <input type="text" \
        class="form-control" \
        name="building_name" \
        value="ASDF">

Который работает совершенно нормально во всех аспектах, указанных в вопросе.

Вернуться на верх