Skip to main content

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>

在学生列表页,点击编辑按钮,页面跳转到对应学生的编辑页,如下图所示。

image-20260106171558648

image-20260106171539798

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按钮。

现在来测试一下弹窗效果。在学生列表页,点击编辑,如下图所示。

image-20260106173709353

4.真正难的地方:数据校验

好,下面是这一节真正的核心

当表单提交后,编辑的流程和新增一样,我们需要编写2个方法:

  • form_valid: 验证通过
  • form_invalid: 验证未通过

我们先不急编写代码,先来分析一下需求。

在学生表字段中,student_numberstudent_name比较特殊。因为我们在新增学生并同步更新auth_user表时,使用了如下代码:

# 写入到auth_user表
username = student_name + '_' + student_number
password = student_number[-6:]

所以,如果我们要更改一个学生的学号姓名, 那么就要同步更新auth_user表,这是我们特别需要注意的地方。

image-20260106182416141

接下来,我们实现表单验证的方法。

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()进行加密。

image-20260106185439440

image-20260106185534205

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

image-20260106185652756

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位,效果如下:

image-20260106190121791

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

本章小结

  1. 编辑不是“重新新增”
  2. UpdateView 的正确使用姿势
  3. form.changed_data 的真实价值
  4. 一对一模型如何同步修改
  5. Django 密码必须走加密流程
  6. 一个表单,如何支持新增 + 编辑两种模式

给你一个「下一步可执行动作」

现在我们能新增、能编辑,但用户体验还有两个问题: 1️⃣ 删除没有确认 2️⃣ 批量操作不安全

下一节我们来把『删除学生』做成一个真正敢上线的版本。

小伙伴们,下节见!