16.如何编辑学生信息
新增的时候:
- 没有学生
- 没有 user
- 所有数据都是“新建”
编辑的时候:
- Student 已存在
- User 已存在
- 我们做的是: 👉 在原有数据基础上修改
所以在 Django 里:
- 新增 →
CreateView - 编辑 →
UpdateView
1.创建路由和视图
老规矩,先来创建路由,代码如下:
# 代码位置:students/urls.py
from django.urls import path
from .views import StudentListView,StudentCreateView,StudentUpdateView
urlpatterns = [
path('', StudentListView.as_view(), name='student_list'),
path('create/', StudentCreateView.as_view(), name='student_create'),
# 新增路由
path('<int:pk>/update', StudentUpdateView.as_view(), name='student_update'),
]
接下来,创建视图文件
# 代码位置:students/views.py
class StudentUpdateView(UpdateView):
model = Student
form_class = StudentForm
template_name = 'students/student_form.html'
2.修改列表模版文件,点击显示弹窗
进入学生列表页,找到编辑按钮位置,使用{% url %}标签修改href属性值。
<a href="{% url 'student_update' student.pk %}" class="btn btn-primary btn-sm edit">编辑</a>
在学生列表页,点击编辑按钮,页面跳转到对应学生的编辑页,如下图所示。


3.使用弹窗形式
你这里做的这个决定,非常重要:
编辑不是页面跳转,而是弹窗
所以:
- 不能直接
<a>跳转 - 必须:
- 阻止默认行为
- 判断编辑哪一个数据,然后用 JS 打开弹窗
- 加载对应的 update URL
在students_list.html页面,我们编写编辑的操作流程。
# 代码位置:templates/students/students_list.html
<script>
{% if student.pk %}
<script>
var actionUrl = "{% url 'student_update' student.pk %}";
</script>
{% else %}
<script>
var actionUrl = "{% url 'student_create' %}";
</script>
{% endif %}
// 点击新增部分省略...
// 点击编辑
document.querySelectorAll('.edit').forEach(button => {
button.addEventListener('click', function(e) {
e.preventDefault(); // 阻止跳转
url = this.getAttribute('href')
Swal.fire({
position: "top-end",
html: `<iframe src="${url}" width="100%", height="800px" frameborder="0" > <iframe>`,
width: 600,
showConfirmButton: false
});
})
})
</script>
这里我想帮你点破一个新手常卡的点:
为什么不能用
id?
因为页面上:
- 新增按钮:1 个
- 编辑按钮:N 个
一个HTML页面,id是唯一的,所以编辑的时候,不能用id。我们可以监听所有的class="edit"的button按钮。
现在来测试一下弹窗效果。在学生列表页,点击编辑,如下图所示。

4.真正难的地方:数据校验
好,下面是这一节真正的核心。
当表单提交后,编辑的流程和新增一样,我们需要编写2个方法:
- form_valid: 验证通过
- form_invalid: 验证未通过
我们先不急编写代码,先来分析一下需求。
在学生表字段中,student_number和student_name比较特殊。因为我们在新增学生并同步更新auth_user表时,使用了如下代码:
# 写入到auth_user表
username = student_name + '_' + student_number
password = student_number[-6:]
所以,如果我们要更改一个学生的学号和姓名, 那么就要同步更新auth_user表,这是我们特别需要注意的地方。

接下来,我们实现表单验证的方法。
form_valid()方法
class StudentUpdateView(UpdateView):
def form_valid(self, form):
# 获取学生对象实例(但先不保存)
student = form.save(commit=False)
# ⚠️ 注意:这里必须写成下面这种形式
if 'student_name' in form.changed_data or 'student_number' in form.changed_data:
# 重新生成 username
student.user.username = (
f"{form.cleaned_data.get('student_name')}_"
f"{form.cleaned_data.get('student_number')}"
)
# 使用 set_password(而不是 make_password)
student.user.set_password(
form.cleaned_data.get('student_number')[-6:]
)
# 保存 user
student.user.save()
# 保存 student
student.save()
return JsonResponse({
'status': 'success',
'messages': '操作成功'
}, status=200)
【代码解析】
1️⃣ 使用 commit=False暂时更新
student = form.save(commit=False)
这句话的真实含义是:
表单我先拿到,但我暂时不写数据库
因为你要先判断一件事:
学生名 / 学号有没有被改?
2️⃣ 判断“是否修改字段”的正确方式
查看表单中哪些字段变化了,可以使用form.changed_data,代码如下:
if 'student_name' in form.changed_data or 'student_number' in form.changed_data:
👉 只有当 姓名或学号真的被改了
👉 才去改 auth_user
这是编辑功能是否稳定的关键点。
3️⃣ 同步修改 auth_user
- user 和 student 是一对一
- student 改 → user 跟着改
- 不需要再查 User 表
# 重新生成 username
student.user.username = (
f"{form.cleaned_data.get('student_name')}_"
f"{form.cleaned_data.get('student_number')}"
)
# 使用 set_password(而不是 make_password)
student.user.set_password(
form.cleaned_data.get('student_number')[-6:]
)
**注意:**密码不能直接赋值明文,需要使用set_password()进行加密。


我们重点查看auth_user表中的数据,效果如下:

form_invalid()方法
接下来,编写验证不同的方法form_invalid。它主要用于返回错误信息给student_form表单,所以和前面的新增学生时代码相同。
def form_invalid(self, form):
errors = form.errors.as_json()
return JsonResponse({
'status': 'error',
'messages': errors
}, status=400)
下面我们来测试一下。学籍号只填写1位,效果如下:

学籍号填写已经存在的李四同学的学号,效果如下:

本章小结
- 编辑不是“重新新增”
UpdateView的正确使用姿势form.changed_data的真实价值- 一对一模型如何同步修改
- Django 密码必须走加密流程
- 一个表单,如何支持新增 + 编辑两种模式
给你一个「下一步可执行动作」
现在我们能新增、能编辑,但用户体验还有两个问题: 1️⃣ 删除没有确认 2️⃣ 批量操作不安全
下一节我们来把『删除学生』做成一个真正敢上线的版本。
小伙伴们,下节见!
【大熊课堂精品课程】
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