Django模态框多表单编辑:如何传入Instance加载已有数据
Django同一页面多模态表单编辑:传入instance显示已有数据
我在Django应用的同一页面使用多个模态框打开的表单,已通过自定义函数实现基础功能,但作为新手,添加编辑功能时遇到困难——不清楚应在何处传入instance,使表单能够显示该实例的已有数据。
现有代码片段
视图中的表单变量:
edit_employment_form = _get_form(request, EditEmploymentForm, "edit_employment_form_pre")
区分表单的自定义函数:
def _get_form(request, formcls, prefix): data = request.POST if prefix in request.POST else None return formcls(data, prefix=prefix)
完整视图代码(已获取用于筛选实例的employment_id):
@login_required def person_profile(request, person_id): current_user = request.user user = Person.objects.get(user=current_user) people = Person.objects.all() jobs = Job.objects.all() person = Person.objects.get(pk=person_id) employments = Employments.objects.filter(person_id=person_id).order_by("-start_date") workflows = Workflows.objects.filter(person_id=person_id).order_by("-workflow_date") sources = Sources.objects.filter(person_id=person_id).order_by("-source_date") tags = Tags.objects.filter(person_id=person_id) comments = Comments.objects.filter(person_id=person_id) person_calls = ScheduledCalls.objects.filter(person_id=person_id).order_by("-date") scheduled_calls = ScheduledCalls.objects.filter(user_id=user.id).order_by("-date") reminders = Reminders.objects.filter(person_id=person_id) notes = Notes.objects.filter(user_id=person_id) gdpr = GDPR.objects.filter(person_id=person_id).order_by("-is_valid") valid_gdpr_filter = GDPR.objects.filter(person_id=person_id, is_valid="Valid") license_b_filter = Licenses.objects.filter(person_id=person_id, license="B") license_c_filter = Licenses.objects.filter(person_id=person_id, license="C") license_ce_filter = Licenses.objects.filter(person_id=person_id, license="CE") license_95_filter = Licenses.objects.filter(person_id=person_id, license="95") skill_fd_filter = Skills.objects.filter(person_id=person_id, skill="FD experience") skill_op_filter = Skills.objects.filter(person_id=person_id, skill="OP experience") skill_ce_filter = Skills.objects.filter(person_id=person_id, skill="CE driver experience") skill_tl_filter = Skills.objects.filter(person_id=person_id, skill="Team Leading experience") if valid_gdpr_filter: valid_gdpr = GDPR.objects.get(person_id=person_id, is_valid="Valid") end_date_calc = ((valid_gdpr.consent_date + timedelta(days=1095)) - date.today()) days = int(str(end_date_calc).split(" ", 1)[0]) if days > 30: consent_ends_in = "more than a month" elif days > 14: consent_ends_in = "around 2 weeks" elif days < 14: consent_ends_in = "less than 2 weeks!" else: valid_gdpr = None consent_ends_in = None if license_b_filter: license_b = Licenses.objects.get(person_id=person_id, license="B") else: license_b = None if license_c_filter: license_c = Licenses.objects.get(person_id=person_id, license="C") else: license_c = None if license_ce_filter: license_ce = Licenses.objects.get(person_id=person_id, license="CE") else: license_ce = None if license_95_filter: license_95 = Licenses.objects.get(person_id=person_id, license="95") else: license_95 = None if skill_fd_filter: skill_fd = Skills.objects.get(person_id=person_id, skill="FD experience") else: skill_fd = None if skill_op_filter: skill_op = Skills.objects.get(person_id=person_id, skill="OP experience") else: skill_op = None if skill_ce_filter: skill_ce = Skills.objects.get(person_id=person_id, skill="CE driver experience") else: skill_ce = None if skill_tl_filter: skill_tl = Skills.objects.get(person_id=person_id, skill="Team Leading experience") else: skill_tl = None if request.method == "POST": new_employment_form = _get_form(request, EmploymentForm, "new_employment_form_pre") new_application_form = _get_form(request, ApplicationForm, "new_application_form_pre") new_consent_form = _get_form(request, GDPRForm, "new_consent_form_pre") edit_employment_form = _get_form(request, EditEmploymentForm, "edit_employment_form_pre") employment_id = request.POST.get("employment_id") print(employment_id) if new_employment_form.is_bound and new_employment_form.is_valid(): new_employment_form.instance.person_id = person new_employment_form.instance.hired_by = user new_employment_form.save(commit=False) new_employment_form.save() person.person_type = "Current Employee" person.save() candidate_gdpr = GDPR.objects.get(person_id=person_id, is_valid="Valid") candidate_gdpr.is_valid = "Invalid" candidate_gdpr.save() return redirect("person_profile", person_id) if new_application_form.is_bound and new_application_form.is_valid(): new_application_form.instance.person_id = person new_application_form.save(commit=False) new_application_form.save() workflow = Workflows() workflow.workflow_date = date.today() workflow.stage = "New Applicant" workflow.person_id = Person.objects.get(id=person_id) workflow.save() return redirect("person_profile", person_id) if new_consent_form.is_bound and new_consent_form.is_valid(): file = request.POST.get("consent_file") input_date = request.POST.get("consent_date") consent_date = datetime.strptime(input_date, "%Y-%m-%d").date() new_consent_form.instance.consent_file = file new_consent_form.instance.person_id = person new_consent_form.instance.consent_date = consent_date new_consent_form.instance.consent_end_date = consent_date + timedelta(days=1095) new_consent_form.save(commit=False) new_consent_form.save() return redirect("person_profile", person_id) if edit_employment_form.is_bound and edit_employment_form.is_valid(): return redirect("person_profile", person_id) return render(request, "person/person_profile.html", {"person" : person, "people" : people, "jobs" : jobs, "employments" : employments, "workflows" : workflows, "sources" : sources, "tags" : tags, "comments" : comments, "scheduled_calls" : scheduled_calls, "reminders" : reminders, "notes" : notes, "gdpr" : gdpr, "valid_gdpr" : valid_gdpr, "consent_ends_in": consent_ends_in, "license_b" : license_b, "license_c" : license_c, "license_ce" : license_ce, "license_95" : license_95, "skill_fd" : skill_fd, "skill_op" : skill_op, "skill_ce" : skill_ce, "skill_tl" : skill_tl, "person_calls" : person_calls, "scheduled_calls" : scheduled_calls, "new_employment_form" : EmploymentForm(prefix = "new_employment_form_pre"), "new_application_form" : ApplicationForm(prefix = "new_application_form_pre"), "new_consent_form" : GDPRForm(prefix="new_consent_form_pre"), "edit_employment_form" : EditEmploymentForm(prefix="edit_employment_form_pre"), })
解决方案
1. 修改自定义函数支持instance参数
让_get_form能接收并传递instance给表单,这样编辑时就能传入要修改的实例:
def _get_form(request, formcls, prefix, instance=None): data = request.POST if prefix in request.POST else None # 把instance传入表单构造器 return formcls(data, prefix=prefix, instance=instance)
2. 在视图中获取要编辑的Employment实例
不管是GET请求(打开模态框)还是POST请求(提交编辑),都需要先拿到对应的employment_id,再查询出实例:
在视图顶部、if request.method == "POST"之前添加:
# 从POST或GET参数中获取employment_id employment_id = request.POST.get("employment_id") or request.GET.get("employment_id") employment_instance = None if employment_id: try: # 确保是当前person的employment,避免越权 employment_instance = Employments.objects.get(pk=employment_id, person_id=person_id) except Employments.DoesNotExist: employment_instance = None
3. 初始化编辑表单时传入instance
- POST请求中:修改初始化
edit_employment_form的代码,传入employment_instance:
edit_employment_form = _get_form(request, EditEmploymentForm, "edit_employment_form_pre", instance=employment_instance)
- GET请求返回时:替换原来直接实例化表单的代码,改用
_get_form并传入实例:
"edit_employment_form" : _get_form(request, EditEmploymentForm, "edit_employment_form_pre", instance=employment_instance),
4. 完善编辑表单的保存逻辑
现在表单已经绑定了实例,直接调用save()就能更新数据:
if edit_employment_form.is_bound and edit_employment_form.is_valid(): edit_employment_form.save() return redirect("person_profile", person_id)
5. 前端传递employment_id
点击编辑按钮时,要把对应employment的ID传递给模态框里的表单,比如用Bootstrap模态框的事件:
- 编辑按钮添加
data-employment-id属性:
<button type="button" data-bs-toggle="modal" data-bs-target="#editEmploymentModal" data-employment-id="{{ emp.id }}"> 编辑工作经历 </button>
- 模态框表单里加一个隐藏字段:
<form method="post" id="editEmploymentForm" prefix="edit_employment_form_pre"> {% csrf_token %} <input type="hidden" name="employment_id" id="employment_id"> <!-- 其他表单字段 --> </form>
- 用JavaScript在模态框显示时赋值:
const editModal = document.getElementById('editEmploymentModal'); editModal.addEventListener('show.bs.modal', function (event) { const button = event.relatedTarget; const empId = button.getAttribute('data-employment-id'); document.getElementById('employment_id').value = empId; });
内容的提问来源于stack exchange,提问作者Satten
相关产品推荐
相关产品推荐

