Skip to main content

11.用弹窗新增学生:把“表单体验”拉到真实项目级别

前一节课,我们已经把 SweetAlert2 跑通了:

  • 能弹窗
  • 能加载 iframe
  • 能显示一个完整页面

但那一节,其实还停留在「演示层面」。

这一节,我们要做一件真正上项目的事情

点击「新增学生」,直接弹出学生表单,并完成保存。

这一步,是很多新手从「会写代码」到「会做系统」的分水岭。

1.先把目标说清楚

这一节我们要实现的效果是:

  1. 学生列表页有一个【新增】按钮
  2. 点击新增
  3. 弹出一个 SweetAlert 弹窗
  4. 弹窗中加载「学生表单页面」
  5. 填写学生信息
  6. 点击保存
  7. 学生数据成功入库

注意一句话:

后端逻辑,我们前面其实已经写过了。

这一节的重点,不是 CRUD, 而是:怎么把已有的 CRUD 用“弹窗方式”呈现出来。

2.老规矩:先创建新增学生的 URL

我们先回到 students/urls.py

新增学生,我们保持和前面班级一致的命名风格:

# 代码位置:students/urls.py
from django.urls import path
from .views import StudentListView,StudentCreateView

urlpatterns = [
path('', StudentListView.as_view(), name='student_list'),
# 新增
path('create/', StudentCreateView.as_view(), name='student_create'),
]

这一步你只要确认一件事:

  • URL 是存在的
  • 名字是 student_create

后面 JS 和模板,都会用到它。

3.创建 StudentCreateView

接下来进入 students/views.py

我们创建一个新增视图类:

from django.views.generic import ListView,CreateView
from .models import Student
from .forms import StudentForm

class StudentListView(ListView):
pass


class StudentCreateView(CreateView):
model = Student
form_class = StudentForm
template_name = 'students/student_form.html'

看到这里,你应该有一种熟悉感。因为在班级管理的新增功能全部应用过。

如果你现在还能跟上,说明你已经真正掌握了 CBV(视图类) 的节奏

4.StudentForm 从哪来?

你会立刻发现一个问题:

StudentForm 还不存在。

这一步千万别慌,这是正常流程。

students 应用下,新建一个文件:

students/
├── forms.py

然后创建表单类:

from django import forms
from .models import Student

class StudentForm(forms.ModelForm):
class Meta:
model = Student
fields = '__all__'

这一步我想你记住一句话就够了:

ModelForm = 模型字段的“自动表单版本”。

5.模板策略:新增 & 编辑只用一个页面

接下来是一个非常重要的设计决策

新增学生和编辑学生,页面一模一样:

  • 表单结构一样
  • 字段一样
  • 校验规则一样

所以我们只创建一个模板student_forms.html。 此外,我们还需要引入SweetAlert2弹窗文件。目录结果如下:

static/
└── css/
└── sweetalert2.css
└── js/
└── sweetalert2.js

templates/
└── students/
└── student_form.html

student_form.html模板内容显示通用表单结构,代码如下:

{% load static %}
<link rel="stylesheet" href="{% static 'css/form.css' %}">
<link rel="stylesheet" href="{% static 'css/sweetalert2.css' %}" >
<div class="container">
{% if student.pk %}
<h2>编辑学生信息</h2>
{% else %}
<h2>添加学生信息</h2>
{% endif %}
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}:</label>
{{ field }}
{% if field.help_text %}
<small class="form-text text-muted"> {{ field.help_text}} </small>
{% endif %}
</div>
{% endfor %}
<div class="handleButton">
<button type="submit" id="saveButton">保存</button>
<button type="button" id="cancelButton" onclick="window.parent.Swal.close();">取消</button>
</div>
</form>
</div>

【代码解析】

  1. {% if %}判断主键student.pk是否存在。如果不存在,表示新增。如果存在,表示修改。

  2. field.help_text 👉 来自 Model 中的 help_text

  3. 取消按钮 👉 直接关闭父级弹窗,而不是提交表单

6.直接访问 create,先确认后端没问题

在接入弹窗之前,一定要先验证后端页面是 OK 的

直接访问:

/students/create/

如果你能看到学生表单页面, 说明:

  • URL 正确
  • View 正确
  • Form 正确
  • Template 正确

这一步千万别省,否则后面 JS 出问题你会非常难排查。

访问127.0.0.1:8000/students/create/, 运行效果如下所示:

image-20260105144618989

7.点击新增 → 弹窗加载表单

现在我们回到 学生列表页模板

在这里你已经有一个「新增」按钮,比如:

<button id="add">新增</button>

⚠️ 注意一句话:

ID 在一个页面中必须唯一。

所以后面 JS,我们优先用 id 来找它。

在students_list.html学生列表页模板底部,我们写 JS:

# 代码位置:templates/students/students_list.html
<script>
document.getElementById('add').addEventListener('click', function () {
Swal.fire({
html: `
<iframe src="{% url 'student_create' %}"
width="600"
height="800"
frameborder="0">
</iframe>
`,
position: 'top-end',
showConfirmButton: false
})

})
</script>

这里有一个非常关键的知识点,一定要听清楚。

你可能已经注意到了:

` 反引号 `

而不是单引号或双引号。

原因很简单:

我们在 JS 字符串里,又嵌套了 Django 的 {% url %}

如果你用单引号 / 双引号:

  • JS 会乱
  • Django 也会乱

模板字符串(Template Literal) 可以完美解决这个问题。

你可以把它理解成:

JavaScript 里的 f-string。

8.iframe 被拒绝访问?

第一次点新增按钮,你大概率会看到一个提示:

拒绝连接 / refused to connect

使用浏览器的审查功能,点击console查看错误信息,如下图所示。 image-20260105145835291

这不是你写错了。

这是浏览器的 X-Frame-Options 安全策略

解决方式也很简单。

settings.py 配置文件中的最后,加一行:

X_FRAME_OPTIONS = 'SAMEORIGIN'

意思是:

允许同源页面用 iframe 加载。

这是我们现在这个项目完全合理的场景

再次点击新增按钮,运行效果如下所示:

image-20260105151155610

9.细节优化:去掉 SweetAlert 默认按钮

在弹出的新增学生弹窗中,你会发现有一个User:下拉列表。这就是关联的auth_user表数据。但实际开发过程中,并不需要去选择,所以我们可以把这个字段隐藏,并且重新排列字段的顺序。

那么,只需要去配置model模型即可,代码如下:

from django import forms
from .models import Student

class StudentForm(forms.ModelForm):
class Meta:
model = Student
# fields = '__all__' #
# 设定显示的字段和顺序
fields = ['student_name', 'student_number', 'grade', 'gender', 'birthday', 'contact_number', 'address']

再次点击新增按钮,运行效果如下图所示:

image-20260105151838266

本节小结

这一节,你完成了几件非常重要的事情:

  • 把 Django 的新增页面“嵌入”到弹窗中
  • 前端展示和后端逻辑完全解耦
  • 使用 SweetAlert 承载真实业务页面
  • 理解了 iframe + 同源策略的实际用途

你现在写的,已经不是教学 Demo,而是 真实可交付的系统结构

下一步

下一节,我们就来做这件事:

  1. 验证用户提交的信息
  2. 保存用户提交的信息

到那一步,你的项目会非常“像商业系统”。

好,这一节我们就到这里。 小伙伴们,下节再见 👋