JavaScript动态生成表单时Django模板标签未渲染,仅显示{{form}}的问题求助
问题根源分析
你遇到的核心问题是:Django的模板标签(比如{{ form }}、{% for %})是在后端服务器渲染HTML时解析的,而你的JavaScript代码是在前端浏览器运行的,浏览器完全不认识这些Django语法,所以直接把它们当成普通文本显示了。
简单来说,后端渲染是"提前加工"HTML,前端JS只能拿到加工后的成品,没法让浏览器再回头找Django解析模板标签。下面给你两种可行的解决方案,从简单到进阶:
方案一:提前渲染表单,用CSS切换显示(最适合你的场景)
这种方法不需要AJAX,直接把两个表单提前在页面里渲染好,默认隐藏,点击按钮时只切换显示状态即可。
1. 修改HTML模板
把两个表单都写在页面中,用display:none默认隐藏:
<script src="{% static '/js/onclick.js' %}"></script> <title>add appointment </title> </head> <body> <div class="container"> <button name="type" class="button1" id="button1">register patient</button> <button name="type" class="button2" id="button2">non register patient</button> <div id='form'> <!-- 注册患者表单(默认隐藏) --> <div id="form-registered" style="display:none;"> <form action="{% url 'create_appointement_register_patient' %}" method="POST"> <p> <label for="patients">select a patient</label> <select name="patients" id="patients"> <option value="">-- select a patient --</option> {% for patient in patients %} <option value="{{patient}}">{{patient}}</option> {%empty%} <option value="nothing">nothing</option> {% endfor %} </select> </p> {{ form_registered.media }} {{ form_registered.as_p }} {% csrf_token %} <button type="submit"> ok </button> </form> </div> <!-- 非注册患者表单(默认隐藏) --> <div id="form-non-registered" style="display:none;"> <form action="{% url 'create_appointement_non_register_patient' %}" method="POST"> {{ form_non_registered.media }} {{ form_non_registered.as_p }} {% csrf_token %} <button type="submit"> ok </button> </form> </div> </div> </div>
2. 修改视图函数
在主视图(比如你的create_appointement视图)中,同时传递两个表单实例给模板:
@login_required def create_appointement(request): if not (request.user.is_doctor() or request.user.is_reception()): return HttpResponseRedirect(reverse("create_appointement")) # 初始化两个表单 form_registered = AppointmentForm_2() form_non_registered = AppointmentForm_3() user2 = get_user_model() patients = user2.objects.filter(type_of_user=TypeOfUser.PATIENT) return render(request, 'appointement/add_appointement_options.html', { 'form_registered': form_registered, 'form_non_registered': form_non_registered, 'patients': patients })
3. 简化JavaScript
现在JS只需要切换两个表单的显示状态:
document.addEventListener('DOMContentLoaded', function() { const formRegistered = document.getElementById("form-registered"); const formNonRegistered = document.getElementById("form-non-registered"); document.getElementById("button1").onclick = function() { formNonRegistered.style.display = "none"; formRegistered.style.display = "block"; } document.getElementById("button2").onclick = function() { formRegistered.style.display = "none"; formNonRegistered.style.display = "block"; } })
方案二:用AJAX动态获取渲染好的表单(进阶场景)
如果你的表单需要根据用户操作动态生成(比如依赖之前的选择),可以用AJAX从后端请求已经渲染好的表单HTML,再插入到页面中。
1. 创建专门返回表单的视图
from django.http import HttpResponse @login_required def get_registered_patient_form(request): if not (request.user.is_doctor() or request.user.is_reception()): return HttpResponse("Unauthorized", status=401) form_app = AppointmentForm_2() user2 = get_user_model() patients = user2.objects.filter(type_of_user=TypeOfUser.PATIENT) # 渲染单独的表单模板片段 return render(request, 'appointement/registered_form_fragment.html', { 'form': form_app, 'patients': patients }) @login_required def get_non_registered_patient_form(request): if not (request.user.is_doctor() or request.user.is_reception()): return HttpResponse("Unauthorized", status=401) form_app = AppointmentForm_3() return render(request, 'appointement/non_registered_form_fragment.html', { 'form': form_app })
2. 创建表单模板片段
registered_form_fragment.html:
<form action="{% url 'create_appointement_register_patient' %}" method="POST"> <p> <label for="patients">select a patient</label> <select name="patients" id="patients"> <option value="">-- select a patient --</option> {% for patient in patients %} <option value="{{patient}}">{{patient}}</option> {%empty%} <option value="nothing">nothing</option> {% endfor %} </select> </p> {{ form.media }} {{ form.as_p }} {% csrf_token %} <button type="submit"> ok </button> </form>
non_registered_form_fragment.html:
<form action="{% url 'create_appointement_non_register_patient' %}" method="POST"> {{ form.media }} {{ form.as_p }} {% csrf_token %} <button type="submit"> ok </button> </form>
3. 修改JavaScript用AJAX请求
document.addEventListener('DOMContentLoaded', function() { const formContainer = document.getElementById("form"); // 获取Django的CSRF Token,用于验证请求 const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value; document.getElementById("button1").onclick = async function() { try { const response = await fetch("{% url 'get_registered_patient_form' %}", { method: 'GET', headers: {'X-CSRFToken': csrfToken} }); if (response.ok) { const html = await response.text(); formContainer.innerHTML = html; } else { formContainer.innerHTML = "<p>Failed to load form</p>"; } } catch (err) { formContainer.innerHTML = "<p>Error loading form</p>"; } } document.getElementById("button2").onclick = async function() { try { const response = await fetch("{% url 'get_non_registered_patient_form' %}", { method: 'GET', headers: {'X-CSRFToken': csrfToken} }); if (response.ok) { const html = await response.text(); formContainer.innerHTML = html; } else { formContainer.innerHTML = "<p>Failed to load form</p>"; } } catch (err) { formContainer.innerHTML = "<p>Error loading form</p>"; } } })
4. 添加路由到urls.py
urlpatterns = [ # 新增的表单请求路由 path('appointment/registered-form/', views.get_registered_patient_form, name='get_registered_patient_form'), path('appointment/non-registered-form/', views.get_non_registered_patient_form, name='get_non_registered_patient_form'), # 原有的创建预约路由 path('appointment/create-registered/', views.create_appointement_register_patient, name='create_appointement_register_patient'), path('appointment/create-non-registered/', views.create_appointement_non_register_patient, name='create_appointement_non_register_patient'), ]
内容的提问来源于stack exchange,提问作者houhou
相关产品推荐
相关产品推荐

