Django使用Ajax实现表单自动填充时元素重复及选中值保留问题
问题根因
你现在遇到元素重复的核心原因是:Ajax请求触发后,后端返回了完整的页面模板(包含外层标题、页面结构),而你直接把整个返回内容替换到了现有<form>标签内部,相当于把完整页面嵌套进了表单里,自然会出现重复元素。
解决方案
1. 拆分表单模板
先把表单的核心字段部分抽成独立的局部模板,命名为_well_form_fields.html,仅保留表单内部的核心内容,不要外层页面结构:
{% load crispy_forms_tags %} {% csrf_token %} <div class="border p-2 mb-3 mt-3 border-secondary"> <div class="form-row"> <div id= "PUITS" class="form-group col-md-3 mb-0"> {{form.PUITS|as_crispy_field}} </div> <div class="form-group col-md-3 mb-0"> {{ form.CS |as_crispy_field}} </div> <div class="form-group col-md-3 mb-0"> {{ form.MODE|as_crispy_field}} </div> <div class="form-group col-md-3 mb-0"> {{ form.SITUATION |as_crispy_field}} </div> </div> <div class="form-row"> <div class="form-group col-md-3 mb-0"> {{ form.DATE_TEST|as_crispy_field }} </div> <div id='DUSE' class="form-group col-md-3 mb-0"> {{ form.DUSE|as_crispy_field }} </div> <div class="form-group col-md-3 mb-0"> {{ form.PRES_TBG|as_crispy_field }} </div> <div class="form-group col-md-3 mb-0"> {{ form.PRES_CSG|as_crispy_field }} </div> </div> <div class="form-row"> <div class="form-group col-md-8 mb-0"> {{ form.OBSERVATION|as_crispy_field }} </div> </div> </div> <input class="btn btn-success mb-4" type="submit" value="ADD Record">
修改原来的完整页面模板Add_wellMntr2.html,在表单内部新增一个容器用来包裹动态加载的字段部分,引用刚才的局部模板:
<!-- 原有外层页面结构保持不变 --> <form method="POST" id="SurveillanceDesPuits_F" data-record-url="{% url 'Add_wellMntr' %}"> <!-- 新增容器用于动态替换 --> <div id="form-fields-wrapper"> {% include 'measure/Surveill_Wells/_well_form_fields.html' %} </div> </form> <!-- 原有script部分保持不变,后续会修改Ajax逻辑 -->
2. 修改后端视图逻辑
调整CreateWellMon函数,区分普通页面请求和Ajax请求,Ajax请求只返回局部模板内容:
from django.core.exceptions import ObjectDoesNotExist def CreateWellMon(request): if request.method == 'POST': form = SurveillanceDesPuits_F(request.POST or None) if form.is_valid(): form.instance.author = request.user form.save() return redirect('WellMonitor') else: form = None try: PUITS_id = request.GET.get('PUITS') # 按id倒序取对应井的最新记录 record = SurveillanceDesPuits.objects.filter(PUITS_id__id__exact=PUITS_id).order_by('-id').first() if not record: raise ObjectDoesNotExist form = SurveillanceDesPuits_F(instance=record) except ObjectDoesNotExist: # 取不到对应井记录时取全表最新记录 latest_record = SurveillanceDesPuits.objects.all().order_by('-id').first() form = SurveillanceDesPuits_F(instance=latest_record) # 判断是否为Ajax请求 if request.headers.get('x-requested-with') == 'XMLHttpRequest': # Ajax请求返回局部表单模板 return render(request, 'measure/Surveill_Wells/_well_form_fields.html', {'form': form}) # 普通请求返回完整页面 return render(request, 'measure/Surveill_Wells/Add_wellMntr2.html', {'form': form})
3. 调整前端Ajax逻辑
修改JS代码,仅替换表单字段容器的内容,不要替换整个form标签,同时改用事件委托保证动态加载后的下拉框事件正常触发:
$(document).ready(function(){ // 事件委托适配动态加载的表单元素 $(document).on('change', "#id_PUITS", function(){ var url = $("#SurveillanceDesPuits_F").attr("data-record-url"); var PUITSId = $(this).val(); $.ajax({ type: 'GET', url: url, data: {'PUITS': PUITSId}, success: function (data){ // 只替换字段容器内容,不会引入外层页面结构避免重复 $('#form-fields-wrapper').html(data); // 后端返回的form已经绑定了选中井的对应记录,下拉框会自动保留选中值,无需额外处理 } }); return false; }); });
内容的提问来源于stack exchange,提问作者tibas
相关产品推荐
相关产品推荐

