11.用弹窗新增学生:把“表单体验”拉到真实项目级别
前一节课,我们已经把 SweetAlert2 跑通了:
- 能弹窗
- 能加载 iframe
- 能显示一个完整页面
但那一节,其实还停留在「演示层面」。
这一节,我们要做一件真正上项目的事情:
点击「新增学生」,直接弹出学生表单,并完成保存。
这一步,是很多新手从「会写代码」到「会做系统」的分水岭。
1.先把目标说清楚
这一节我们要实现的效果是:
- 学生列表页有一个【新增】按钮
- 点击新增
- 弹出一个 SweetAlert 弹窗
- 弹窗中加载「学生表单页面」
- 填写学生信息
- 点击保存
- 学生数据成功入库
注意一句话:
后端逻辑,我们前面其实已经写过了。
这一节的重点,不是 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>
【代码解析】
-
{% if %}判断主键student.pk是否存在。如果不存在,表示新增。如果存在,表示修改。 -
field.help_text👉 来自 Model 中的help_text -
取消按钮 👉 直接关闭父级弹窗,而不是提交表单
6.直接访问 create,先确认后端没问题
在接入弹窗之前,一定要先验证后端页面是 OK 的。
直接访问:
/students/create/
如果你能看到学生表单页面, 说明:
- URL 正确
- View 正确
- Form 正确
- Template 正确
这一步千万别省,否则后面 JS 出问题你会非常难排查。
访问127.0.0.1:8000/students/create/, 运行效果如下所示:

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查看错误信息,如下图所示。

这不是你写错了。
这是浏览器的 X-Frame-Options 安全策略。
解决方式也很简单。
在 settings.py 配置文件中的最后,加一行:
X_FRAME_OPTIONS = 'SAMEORIGIN'
意思是:
允许同源页面用 iframe 加载。
这是我们现在这个项目完全合理的场景。
再次点击新增按钮,运行效果如下所示:

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']
再次点击新增按钮,运行效果如下图所示:

本节小结
这一节,你完成了几件非常重要的事情:
- 把 Django 的新增页面“嵌入”到弹窗中
- 前端展示和后端逻辑完全解耦
- 使用 SweetAlert 承载真实业务页面
- 理解了 iframe + 同源策略的实际用途
你现在写的,已经不是教学 Demo,而是 真实可交付的系统结构。
下一步
下一节,我们就来做这件事:
- 验证用户提交的信息
- 保存用户提交的信息
到那一步,你的项目会非常“像商业系统”。
好,这一节我们就到这里。 小伙伴们,下节再见 👋
【大熊课堂精品课程】
Python零基础入门动画课: https://www.bilibili.com/cheese/play/ss7988
Django+Vue:全栈开发: https://www.bilibili.com/cheese/play/ss8134
PyQT6开发桌面软件: https://www.bilibili.com/cheese/play/ss12314
Python办公自动化: https://www.bilibili.com/cheese/play/ss14990
Cursor AI编程+MCP:零基础实战项目课: https://www.bilibili.com/cheese/play/ss105194189
Pandas数据分析实战: https://www.bilibili.com/cheese/play/ss734522035
AI大模型+Python小白应用实战: https://www.bilibili.com/cheese/play/ss3844