You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 14:42:45