Упорядочивание поля DELETE в наборе форм
У меня есть Django formset, который отображается в виде таблицы с одной формой на таблицу. Я хотел бы добавить флажок в первый столбец таблицы, чтобы пользователь мог отметить его, если он хочет удалить строку (форму).
У меня есть javascript для управления удалением строки набора форм (формы) и модификации формы управления на передней стороне, но у меня возникает проблема, когда я добавляю поле DELETE в форму. Я использовал ссылку на решение в modify DELETE widget, чтобы я мог добавить класс "delete" ко всем моим полям удаления для использования в CSS и JS на передней стороне. Когда поле DELETE добавлено, оно всегда является последним полем в форме. Я бы хотел, чтобы оно было первым.
models.py
class ModelOne(models.Model):
attr_one = models.CharField(max_length=16)
attr_two = models.CharField(max_length=16)
forms.py
class BaseFormOneFormset(BaseModelFormSet):
def add_fields(self, form, index) -> None:
super().add_fields(form, index)
form.fields[DELETION_FIELD_NAME].widget = forms.CheckboxInput(attrs={'class':"delete"})
form.fields["id"].widget=forms.HiddenInput(attrs={'class':'pk'})
class FormOne(forms.ModelForm):
class Meta:
model = ModelOne
attr_one = forms.CharField(max_length=16,
required=True,
label="attr_one",
widget=forms.TextInput(attrs={'size':5,'class':'required '}))
attr_two = forms.CharField(max_length=16,
required=True,
label="attr_two",
widget=forms.TextInput(attrs={'size':5,'class':'required '}))
views.py
def view_one(request):
formset_factory_one = modelformset_factory( ModelOne,
FormOne,
formset=BaseFormOneFormset,
extra=0,
can_delete=True)
formset_one = formset_factory_one(query_set=FormOne.objects.all(),
prefix="formone")
return render(request, "app_one/template_one.html",{"formset_one":formset_one})
template_one.html
<table id="tbl-id">
<thead id="tbl-head-id">
<tr>
{% for form in formset_one|slice:":1" %}
{% for field in form.visible_fields %}
<th>{{field.label|safe}}</th>
{% endfor %}
{% endfor %}
</tr>
</thead>
<tbody id="tbl-body-id">
{% for form in formset_one %}
<tr id="row{{forloop.counter0}}-id" class="formset-row">
{% for field in form.visible_fields %}
<td>
{{field}}
</td>
{% endfor %}
{% for field in form.hidden_fields %}
<td hidden >{{field}}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Таблица результатов
изображение результирующей html-таблицы
Испробованные решения
Я уже пытался установить Form.field_order как в FormOne объявлении класса
class FormOne(forms.ModelForm):
field_order = [ DELETION_FIELD_NAME, "attr_one", "attr_two"]
и в методе BaseFormset.add_fields
def add_fields(self, form, index) -> None:
super().add_fields(form, index)
form.fields[DELETION_FIELD_NAME].widget = forms.CheckboxInput(attrs={'class':"delete"})
form.fields["id"].widget=forms.HiddenInput(attrs={'class':'pk'})
form.field_order = [ DELETION_FIELD_NAME, "attr_one", "attr_two"]
В обоих случаях поле DELETE остается последним в заказе.
Хотя есть способы изменить порядок полей DELETE, переопределив функцию add_fields() набора форм, это довольно утомительно и сложно.
Однако, если ваша цель - просто вывести DELETE первым или в совершенно другой части страницы, вам повезло. Это легко сделать в шаблоне.
Поле delete может быть явно выведено в шаблоне с помощью {{ form.DELETE }}, что эквивалентно обычному выводу {{ field }}, который вы получаете при итерации через form.fields.
Простой пример, чтобы сначала отобразить поле DELETE:
{# this renders the DELETE field #}
{{ form.DELETE }}
{# now render the other fields #}
{% for field in form.visible_fields %}
{# if check to prevent DELETE rendering twice #}
{% if field.name != 'DELETE' %}
{{ field }}
{% endif %}
{% endfor %}
Применим к коду из вашего вопроса:
<table id="tbl-id">
<thead id="tbl-head-id">
<tr>
{% for form in formset_one|slice:":1" %}
{% for field in form.visible_fields %}
<th>Delete</th>
{% if field.name !='DELETE' %}
<th>{{field.label|safe}}</th>
{% endif %}
{% endfor %}
{% endfor %}
</tr>
</thead>
<tbody id="tbl-body-id">
{% for form in formset_one %}
<tr id="row{{forloop.counter0}}-id" class="formset-row">
<td>
{{ form.DELETE }}
</td>
{% for field in form.visible_fields %}
{% if field.name != 'DELETE' %}
<td>
{{field}}
</td>
{% endif %}
{% endfor %}
{% for field in form.hidden_fields %}
<td hidden >{{field}}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>