Dan*_*iel 3 django formset htmx
我正在使用htmx i制作带有嵌套动态表单集的表单(想要逃避 usign JS,但如果别无选择...)来实例化更多表单集字段以制作动态嵌套表单,但是当我POST时,仅来自1 个实例(最后一个)的数据被 POSTed,表单的其余部分正确 POST,并且获取与Chlid formset Child modelParent model
我阅读了有关如何POST 表单集实例的django 文档,并尝试将其应用到我的代码中,我也知道如何同时发布这 两个实例。对于表单集,我正在向包含子表单集的部分模板发出 htmx get 请求hx-get ,效果很好,唯一的问题是这总是将表单集返回到客户端,因此对于POST数据会重复每个字段的次数,并且只获取最后一个实例中放置的数据,但是我尝试更改表单集上的值以使更多表单直立,这给出了预期的结果,每个表单一个子实例,所以我的问题是htmx以及我调用实例的方式。ParentChildform-0xextra=intextra=intnew Child formset
这是我的代码。(我计划在此表单中嵌套更多子表单集,因此为了方便起见,我将其称为sformset)
****views.py****
def createPlan(request):#Requst for the Parent form
form = PlanForm(request.POST or None)
sformset = StructureFormset(request.POST or None) #Nesting the Child formset
context = {
'form':form,
'sformset':sformset,
}
if request.method == 'POST':
print(request.POST)
if form.is_valid() and sformset.is_valid():
plan = form.save(commit=False)
print(plan)
plan.save()
sform = sformset.save(commit=False)
for structure in sform:
structure.plan = plan
structure.save()
return render(request, 'app/plan_forms.html', context)
def addStructure(request):
sformset = StructureFormset(queryset=Structure.objects.none())#add a empty formset instance
context = {"sformset":sformset}
return render(request, 'app/formsets/structure_form.html', context)
Run Code Online (Sandbox Code Playgroud)
****forms.py****
StructureFormset = modelformset_factory(Structure,
fields = (
'material_type',
'weight',
'thickness',
'provider'
))
Run Code Online (Sandbox Code Playgroud)
****relevant part for plan_forms.html template****
<form method="POST">
{% csrf_token %}
<div class="col-12 px-2">
<div class="row px-3 py-1">
<div class="col-3 px-1">{{ form.format }}</div>
<div class="col-3 px-1">{{ form.pc }}</div>
<div class="col-3 px-1">{{ form.revission }}</div>
<div class="col-3 px-1">{{ form.rev_date }}</div>
</div>
<div class="row px-3 py-1">
<div class="col-3 px-1">{{ form.client }}</div>
<div class="col-3 px-1">{{ form.product }}</div>
<div class="col-3 px-1">{{ form.gp_code }}</div>
<div class="col-3 px-1">{{ form.code }}</div>
</div>
</div>
<div>
<table>
<tbody style="user-select: none;" id="structureforms" hx-sync="closest form:queue">
<!--Structure formset goes here-->
</tbody>
<tfoot>
<a href="" hx-get="{% url 'structure-form' %}" hx-swap="beforeend" hx-target="#structureforms">
Add structure <!--Button to call structure formset-->
</a>
</tfoot>
</table>
</div>
<div class="col-12 px-2">
<div class="row px-4 py-1">{{ form.observation }}</div>
<div class="row px-4 py-1">{{ form.continuation }}</div>
<div class="row px-4 py-1">{{ form.dispatch_conditions }}</div>
<div class="row px-3 py-1">
<div class="col-6 px-1">{{ form.elaborator }}</div>
<div class="col-6 px-1">{{ form.reviewer }}</div>
</div>
</div>
<button type="submit">Submit</button>
</form>
Run Code Online (Sandbox Code Playgroud)
****formsets/structure_form.html****
<tr>
<td class="col-12 px-1">
{{ sformset }}
</td>
</tr>
Run Code Online (Sandbox Code Playgroud)
**** relevant urls.py****
urlpatterns = [
path('create_plan/', views.createPlan, name='create_plan'),
path('htmx/structure-form/', views.addStructure, name='structure-form')]
Run Code Online (Sandbox Code Playgroud)
此外,我使用字段和内联在admin.py中构建的表单正是我想要的原始产品(除了初始表单集和样式的数量)
我使用强大的动态表单集的方法HTMX:
拥有一个呈现表单集实例的视图empty_form(即formset.empty_form)。这将返回一个表单,__prefix__其部分通常包含表单编号(即,而不是,它将是form-0-field_nameform-__prefix__-field_name)。这里的技巧是简单地将 替换__prefix__为适当的表格编号。
@Matt 的答案通过迭代表单并进行相关替换来实现这一点。虽然这工作正常,但我认为更简单的方法是在实例化表单集后更改表单集的前缀。这样,您就不会使用build_new_formset辅助函数。
sformset.management_form在客户端:
渲染plan_forms.html. form-TOTAL_FORMS并使用属性在 HTMX 的 GET 请求中包含表单集的 [隐藏输入字段] 的值hx-vals(请注意,我使用的是 jquery 选择器,这只是为了方便。Vanilla JS 也应该可以工作)。
plan_forms.html
<form method="POST">
{% csrf_token %}
{{sformset.management_form}}
...
<tbody style="user-select: none;" id="structureforms" hx-sync="closest form:queue">
<!--Structure formset goes here-->
</tbody>
<tfoot>
<button hx-get="{% url 'structure-form' %}"
hx-swap="beforeend"
hx-target="#structureforms"
hx-get="{% url 'structure-form' %}"
hx-vals='js:{totalForms: $("#id_form-TOTAL_FORMS").val()}' \\ New>
Add structure <!--Button to call structure formset-->
</button>
</tfoot>
...
</form>
Run Code Online (Sandbox Code Playgroud)
在 htmx 发出请求后,需要更新表单集中的表单总数(每次添加表单集时都会增加)。如果你想严格使用 HTMX,你可以使用hx-on允许你监听事件并运行内联 JS 的属性。然而,hyperscript由于 isincrement命令,我发现这更容易。
plan_forms.html
<form method="POST">
...
<tbody style="user-select: none;"
id="structureforms"
hx-sync="closest form:queue"
_="on htmx:afterSettle increment #id_form-TOTAL_FORMS's value">
<!--Structure formset goes here-->
</tbody>
...
</form>
Run Code Online (Sandbox Code Playgroud)
然后你可以在你的视图中处理请求: views.py
...
def createPlan(request): #Requst for the Parent form
form = PlanForm(request.POST or None)
sformset = StructureFormset(request.POST or None) #Nesting the Child formset
...
def addStructure(request):
sformset = StructureFormset(queryset=Structure.objects.none()).empty_form # Creates an empty formset
form_number = int(request.GET.get("totalForms")) - 1 # forms are numbered from 0, so they will always be 1 less than formset's total forms.
sformset.prefix = sformset.prefix.replace("__prefix__", str(form_number)) # override the formset's prefix, replacing the __prefix__
context = {"sformset":sformset}
return render(request, 'app/formsets/structure_form.html', context)
Run Code Online (Sandbox Code Playgroud)
我想差不多就是这样了。
注释
您hx-vals可以使用hx-include
...
hx-include='[name="form-TOTAL_FORMS"]'
...
Run Code Online (Sandbox Code Playgroud)
鉴于addStructure您必须通过以下方式获得价值request.GET.get("form0TOTAL_FORMS")
| 归档时间: |
|
| 查看次数: |
1789 次 |
| 最近记录: |