如何将Django Formset以列格式展示并保留原有JavaScript功能?
解决Django Formset列布局+保留JS功能的方案
看起来你已经搞定了Formset的JS动态功能,现在就差把表单改成列格式啦~ 我来给你两种常见的列布局方案,都能完美兼容你现有的JS功能:
方案1:让Formset的每个表单实例并排显示(一行N个表单)
适合你想把多个表单条目横向排列的场景,比如一行放2个表单:
修改后的HTML代码
<div class='col-sm-10 col-sm-offset-1'> <h1> Enter scheme of entries</h1> <form action='' method='POST'> {% csrf_token %} <div class='btn-group mb-3'> <input class='btn btn-primary' type='submit' value='Save' /> <a class='btn btn-default' href='/'>Cancel</a> </div> {{ formset.management_form }} <!-- 用row包裹所有表单,每个表单占半列 --> <div id="formset-container" class="row g-4"> {% for form in formset %} <div class="formset-item col-sm-6"> {{ form }} <!-- 如果开启了删除功能,添加删除按钮 --> {% if formset.can_delete %} <button type="button" class="btn btn-danger remove-form mt-2">Remove</button> {% endif %} </div> {% endfor %} </div> <button type="button" id="add-form" class="btn btn-success mt-3">Add Another Entry</button> </form> </div>
调整对应的JS代码(确保新增表单也带列布局)
如果你的原有JS是处理添加/删除表单的,只要修改克隆逻辑,让新表单也包裹在col-sm-6的容器里:
document.addEventListener('DOMContentLoaded', function() { const addBtn = document.getElementById('add-form'); const formContainer = document.getElementById('formset-container'); const totalFormsInput = document.getElementById('id_form-TOTAL_FORMS'); let formCount = parseInt(totalFormsInput.value); // 新增表单逻辑 addBtn.addEventListener('click', function() { // 克隆第一个带列布局的表单容器 const newFormWrapper = document.querySelector('.formset-item').cloneNode(true); // 替换所有字段的索引(把form-0改成form-[当前计数]) newFormWrapper.innerHTML = newFormWrapper.innerHTML.replace(/form-\d+/g, `form-${formCount}`); // 清空新表单的输入值 newFormWrapper.querySelectorAll('input, select, textarea').forEach(field => { field.value = ''; field.checked = false; field.selectedIndex = 0; }); // 给新的删除按钮绑定事件 newFormWrapper.querySelector('.remove-form').addEventListener('click', function() { newFormWrapper.remove(); totalFormsInput.value = parseInt(totalFormsInput.value) - 1; }); // 把新表单加入容器 formContainer.appendChild(newFormWrapper); totalFormsInput.value = ++formCount; }); // 初始化现有删除按钮 document.querySelectorAll('.remove-form').forEach(btn => { btn.addEventListener('click', function() { btn.closest('.formset-item').remove(); totalFormsInput.value = parseInt(totalFormsInput.value) - 1; }); }); });
方案2:单个表单的字段分栏显示
如果你想让每个表单内部的字段左右排列(比如一个表单里的两个字段各占半列),可以这样写:
HTML代码片段(替换Formset循环部分)
{{ formset.management_form }} <div id="formset-container" class="space-y-4"> {% for form in formset %} <div class="formset-item p-3 border rounded"> <div class="row g-3"> <!-- 第一个字段占半列 --> <div class="col-sm-6"> {{ form.field_one.label_tag }} {{ form.field_one }} </div> <!-- 第二个字段占半列 --> <div class="col-sm-6"> {{ form.field_two.label_tag }} {{ form.field_two }} </div> <!-- 第三个字段占整列 --> <div class="col-sm-12"> {{ form.field_three.label_tag }} {{ form.field_three }} </div> </div> {% if formset.can_delete %} <button type="button" class="btn btn-danger remove-form mt-2">Remove</button> {% endif %} </div> {% endfor %} </div>
对应的JS代码和方案1基本一致,因为克隆的时候会保留内部的row/col结构,只要确保字段索引更新正确就行。
关键注意点
- 一定要保留
{{ formset.management_form }},这是Django Formset识别表单数量的核心。 - JS里的字段索引替换(
form-\d+)必须正确,否则新增的表单数据不会被后端识别。 - 用Bootstrap的
row和col-*类来控制布局,避免自定义CSS破坏原有样式。
这样调整后,既能实现你想要的列格式,又完全保留原有JS的动态添加/删除功能~
内容的提问来源于stack exchange,提问作者nithin pathak
相关产品推荐
相关产品推荐

