9.实现学生管理列表页
前面几节课,我们已经把班级管理的增、删、改、查 全部跑通了。如下图:




从本节开始,我们将开始完成学生管理功能。
1.接入 students 模块的 URL
老规矩,任何功能,先从 URL 开始。
打开项目的全局路由 urls.py,
我们把学生模块挂进来:
# 代码位置:config/urls.py
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('grades/',include('grades.urls')),
# 新增学生管理
path('students/', include('students.urls')),
]
这一行的意义只有一个:
告诉 Django:学生相关的功能,交给 students 应用。
2.创建 students/urls.py
进入 students 应用目录,新建文件:
students/
├── urls.py
目录结果如下图:

在这里,我们先只做一件事: 👉 学生列表页
# 代码位置: students/urls.py
from django.urls import path
from .views import StudentListView
urlpatterns = [
path('', StudentListView.as_view(), name='student_list'),
]
此时目标非常明确:
访问
/students/,就能看到学生列表。
3.创建 StudentListView
接下来进入 students/views.py。这一步我们已经非常属性。
我们继续使用 Django 的通用类视图:
from django.views.generic import ListView
from .models import Student
class StudentListView(ListView):
model = Student
template_name = 'students/students_list.html'
context_object_name = 'students'
paginate_by = 10
这里我只强调三点:
ListView👉 列表页的标准解法context_object_name👉 模板中用studentspaginate_by👉 后面做分页时直接生效
4.创建学生模型
接下来我们来创建学生模型。我们先来看下添加学生页面效果。

从图片中我们可以看到学生信息内容较多,但是不用慌,和前面创建的班级模型都是类似的。
进入 students/models.py,编写如下代码:
# 代码位置:students/models.py
from django.db import models
from django.contrib.auth.models import User
from grades.models import Grade
# Create your models here.
GENDER_CHOICES = [
('M', '男'),
('F', '女'),
]
class Student(models.Model):
student_number = models.CharField(max_length=20, unique=True,verbose_name='学籍号')
student_name = models.CharField(max_length=50, verbose_name='姓名')
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, verbose_name='性别')
birthday = models.DateField(verbose_name='出生日期', help_text='格式例如:2020-05-01')
contact_number = models.CharField(max_length=20, verbose_name='联系方式')
address = models.TextField(verbose_name='家庭住址')
# user表一对一关联
user = models.OneToOneField(User, on_delete=models.CASCADE) # 设置外键
# 班级表一对多关联
grade = models.ForeignKey(Grade, on_delete=models.CASCADE, related_name='students', verbose_name='班级')
def __str__(self):
return self.student_name
class Meta:
db_table = "student"
verbose_name_plural = "学生信息"
verbose_name = "学生信息"
【代码解析】
-
gender字段我们希望使用下拉列表形式展示,所以设置为
choices=GENDER_CHOICES,而GENDER_CHOICES的值只能是男或女,存储在数据库中时,我们使用M或F来代替。 -
birthday字段是日期类型,使用
DateField类。 -
address字段内容较长,所有使用
TextField类。 -
user字段和Django自带的
auth_user表关联,并且一个student学生对应一个auth_user账号。on_delete=models.CASCADE表示级联删除,也就是说当删除auth_user表中数据时,对应的学生信息也会被删除。
说明:
很多小伙伴反馈说级联删除关系总是容易混淆。例如:
user = models.OneToOneField(User, on_delete=models.CASCADE)
这里表示删除auth_user表时,student表数据很被同时删除。我们可以这样理解记忆:
on_delete 决定的是:
「当 我依赖的对象 被删了,我该怎么办」
而不是**「当我被删了,要不要删别人」**
我们可以通过Django shell 来演示一下。
student表数据如下:

auth_user表数据如下:

注意:student.user_id == auth_user.id
在shell中导入2个模型:

删除student表中,id为6的学生信息,也就是学生名为“张亮”,user_id为7的记录。这只会删除1条记录,也就是student表中记录。如下图:

删除auth_user表中,id为10的学生信息,对应中student表中id为9,学生名为“张欣”的记录。这样会同时删除2条记录:student表1条,auth_user表1条。如下图:

5.执行迁移:让模型真正落库
模型写完,一定要迁移。
顺序永远是这两个命令:
python manage.py makemigrations
python manage.py migrate

执行完成后,你可以做一件很重要的事:
👉 打开数据库工具
👉 看一眼 student 表
👉 确认字段是否和你预期一致
这是一个非常专业的习惯。
如下图:

当我第一次看到生成student表字段时,心中有这样的疑惑,为什么模型中定义的user字段:
user = models.OneToOneField(User, on_delete=models.CASCADE) # 设置外键
但是生成的数据表中,却变成了user_id字段。
这是Django在ORM中进行了处理,它并不会在数据库中真的创建名叫 user 的字段,而是会自动创建:
user_id。这是一个外键字段(ForeignKey / OneToOneField 本质上都是外键),Django 的命名约定就是:
{字段名}_id
例如user_id =2 , 那么它就对应着auth_user表中id=2的对象。从而实现了关联关系,后面我们会使用到。
6.创建学生列表模板
创建完了view视图,Model模型,那么接下来,我们创建模板文件。
MVT是Django框架的核心主线,我们学习时要牢牢记住这一点。
在templates下创建students文件夹,在其下面创建students_list.html文件。目录结构如下:
templates/
└── students/
└── students_list.html
如下图 所示。

这一页我们先不追求“炫”, 只做三件事:
- 能访问
- 能显示数据
- 为后续弹窗留好结构
模板内容你可以直接参考班级列表,稍作修改即可。
Students_list.html代码如下:
{% extends 'base.html' %}
{% block content %}
<div class="right">
<div class="top">
<div class="tool">
<div class="class-info">
<form method="get" action="/students/">
<span>班级: </span>
<select name="grade">
<option value="" selected="">请选择班级</option>
</select>
<span>姓名/学号:</span>
<input type="text" name="search">
<input type="submit" value="搜索">
</form>
</div>
<div class="actions">
<button type="button" class="add" id="add">新增</button>
</div>
</div>
</div>
<div class="bottom">
<table>
<thead>
<tr>
<th><input type="checkbox" id="select-all"></th>
<th>姓名</th>
<th>班级</th>
<th>学号</th>
<th>性别</th>
<th>生日</th>
<th>联系电话</th>
<!-- <th>地址</th> -->
<th>操作</th>
</tr>
</thead>
<tbody>
{% for student in students %}
<tr>
<td><input type="checkbox" name="student_ids" value="{{ student.pk }}"></td>
<td>{{ student.student_name }}</td>
<td>{{ student.grade }}</td>
<td>{{ student.student_number }}</td>
<td>{{ student.gender }}</td>
<td>{{ student.birthday }}</td>
<td>{{ student.contact_number }}</td>
<td>
<a href="#" class="btn btn-primary btn-sm edit">编辑</a>
<a href="#" class="btn btn-danger btn-sm del">删除</a>
</td>
</tr>
`{% endfor %}`
</tbody>
</table>
<!-- 分页导航 -->
<div class="pagination">
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
<span>
第 {{ page_obj.number }} 页 /
共 {{ page_obj.paginator.num_pages }} 页
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
</div>
</div>
</div>
{% endblock %}
上面的模版代码与班级管理页面非常类似,主要通过{% for %}标签来遍历所有学生信息。只是现在数据库中还没有学生数据,运行效果如下:

本节小结
表面上,这一节我们好像只是:
- 建了 URL
- 写了 Model
- 配了 ListView
- 建了模板
但实际上,你已经完成了一个非常关键的流程:
Django的MVT。
下一步
下一节,我们正式进入核心:
用 Fetch 实现学生的新增、编辑、删除(无刷新)。
到那一步,你写的已经不是“Django 教程项目”,而是真正的现代 Web 管理系统。
小伙伴们,下节再见 👋
【大熊课堂精品课程】
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