简介基于Python的Django学生信息管理系统是一套面向计算机专业课程设计、毕业设计场景的完整Web项目源码。资源围绕Django框架典型开发流程展开涵盖模型、视图、模板、URL路由、表单及ORM数据库操作适合希望从零理解Python Web应用分层结构的学生开发者。压缩包共1028个文件大小9.38MB包括Python源码、HTML模板、JavaScript脚本、CSS样式、图片素材及依赖配置文件其中152个py文件与136个pyc文件可直接对照学习Django业务逻辑静态资源与模板完整基本可还原运行环境。已有161人浏览学习。与纯文字教程相比这份资料提供了项目根目录结构、settings配置、数据模型和可复用代码片段便于边看源码边理解请求处理流程。通过实际部署调试可掌握Django项目从创建、配置、建模到部署的基本链路获得一套可扩展的学生管理功能基础模块。1. 课程设计里的Django项目值得拆开看的就这几处学期末帮人答辩时常见一类项目学生信息管理系统用的Django能打开、能增删改查问你“ORM查询怎么优化”“UEditor资源为什么加载不出来”就卡壳。这套基于Python的Django框架学生信息管理系统能从一堆课设里跳出来主要在于它不是只写了一个index页面交差而是把Django的models、views、urls、admin和前端静态资源ueditor、font-awesome、bootstrap串成了一条完整的开发链路。对计算机专业做课程设计或毕业设计的人来说这套代码的价值在于你能看到学生表设计、班级外键关系、后台管理注册、模板渲染和静态资源挂载是怎么互相咬合的而不是背了一堆Django概念却拼不出一个能跑的项目。下文按Django的开发主线拆开讲每一步都给能直接用的配置和代码。2. 项目骨架与settings.py核心配置先把Django的地基打对2.1 目录结构里每个文件是干什么的解压项目后根目录是Django-Stu-master这是一个标准的Django 2.x/3.x项目布局。第一件事不是急着看views.py而是先把manage.py的位置、app的划分、templates和static的挂载方式摸清楚因为课程设计项目最常见的翻车点就是改了几个文件后项目启动报错却根本不知道该去哪个文件排查。典型目录结构如下和摘要描述一致Django-Stu-master/ ├── manage.py # 命令行入口runserver / migrate / createsuperuser ├── requirements.txt # 依赖清单Django版本、mysqlclient等 ├── app_name/ # Django应用目录如student、system之类 │ ├── models.py # 数据模型学生表、班级表定义处 │ ├── views.py # 视图逻辑请求处理和返回渲染 │ ├── urls.py # 该app的路由映射 │ ├── forms.py # 表单定义注册和录入时做校验 │ ├── admin.py # 后台管理配置注册模型到django-admin ├── DjangoStu/ # 项目配置目录与app区分 │ ├── settings.py # 全局配置数据库、INSTALLED_APPS、静态文件 │ ├── urls.py # 根路由入口指向app的urls ├── templates/ # HTML模板Django模板语言渲染数据 ├── static/ # CSS/JS/图片等静态资源 ├── media/ # 用户上传文件头像、图片等对前端开发转过来说这个结构不算复杂。manage.py就相当于package.json里的script命令入口settings.py则是对应vite.config.js加环境变量配置的结合体。课程设计时大家复制粘代码往往犹豫“这个文件该放哪”其实只要按上面的目录放路径就不会乱。2.2 从零初始化一个同结构Django环境假设你拿到的是纯净环境想复现这个项目完整的初始化步骤是这样# 创建虚拟环境避免污染系统Python python -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate # 安装依赖 pip install -r requirements.txt # 创建项目和app如果是从零开始 django-admin startproject DjangoStu . python manage.py startapp student # 初始化数据库迁移 python manage.py makemigrations python manage.py migrate # 创建后台管理员账号 python manage.py createsuperuser # 启动开发服务器 python manage.py runserver 0.0.0.0:8000这里的命令顺序不能乱。makemigrations是把models.py里的类转换成迁移文件migrate才是真正在数据库里建表。新手最常见的错误是改了models.py后直接重启服务导致报“no such table”错误这就是因为没做迁移。createsuperuser是必须的否则后面django-admin登录不了。2.3 settings.py里最值得关注的四块配置这个项目的settings.py配置了应用注册、数据库、模板路径、静态文件路径。我挑出课设阶段最需要吃透的部分# settings.py 关键片段 INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, student, # 自己创建的应用 ] DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: student_db, USER: root, PASSWORD: your_password, HOST: 127.0.0.1, PORT: 3306, } } TEMPLATES [ { BACKEND: django.template.backends.django.DjangoTemplates, DIRS: [BASE_DIR / templates], # 模板目录 APP_DIRS: True, OPTIONS: { context_processors: [ django.template.context_processors.debug, django.template.context_processors.request, django.contrib.auth.context_processors.auth, django.contrib.messages.context_processors.messages, ], }, }, ] STATIC_URL /static/ STATICFILES_DIRS [BASE_DIR / static] # 开发环境静态文件目录 MEDIA_URL /media/ MEDIA_ROOT BASE_DIR / media数据库用了MySQL而不是默认的SQLite这是这类管理系统的常见选择。如果你的环境还没装mysqlclient在这运行migrate前先执行pip install mysqlclientLinux环境下如果编译报错需要先装依赖包Windows下如果装不上改用pip install pymysql # 然后在DjangoStu/__init__.py里加 # import pymysql # pymysql.install_as_MySQLdb()提示课程设计答辩时考官经常问“为什么DATABASES里的ENGINE不直接用mysql”回答要点是Django官方对MySQL的支持需要经过一个适配层mysqlclient是C扩展实现性能最好pymysql是纯Python实现方便但性能略差。INSTALLED_APPS里如果把student这个app漏掉后面运行makemigrations时Django会提示“Cannot find models”看不到任何模型变化错误提示很隐晦。检查顺序是app是否在INSTALLED_APPS里注册了再查models.py是否真的定义了模型类。3. models.py中数据模型设计与ORM查询学生管理系统的核心逻辑3.1 学生表、班级表如何建模学生信息管理系统里最核心的表是学生表Student其次是班级表Class或学院表Department。这个项目在models.py中建了一张学生表和一张班级表班级对学生是一对多关系——一个班级有多个学生一个学生只属于一个班级。完整的模型设计代码# student/models.py from django.db import models from django.utils import timezone class Grade(models.Model): 班级表 name models.CharField(max_length50, verbose_name班级名称, uniqueTrue) head_teacher models.CharField(max_length20, verbose_name班主任) class Meta: db_table grade # 指定表名 verbose_name 班级 verbose_name_plural verbose_name def __str__(self): return self.name class Student(models.Model): 学生信息表 GENDER_CHOICES ( (M, 男), (F, 女), ) student_no models.CharField(max_length20, verbose_name学号, uniqueTrue) name models.CharField(max_length30, verbose_name姓名) gender models.CharField(max_length2, choicesGENDER_CHOICES, verbose_name性别) age models.PositiveIntegerField(verbose_name年龄) grade models.ForeignKey(Grade, on_deletemodels.CASCADE, verbose_name所属班级) phone models.CharField(max_length11, verbose_name联系电话, blankTrue) email models.EmailField(verbose_name邮箱, blankTrue) address models.TextField(verbose_name家庭住址, blankTrue) created_at models.DateTimeField(defaulttimezone.now, verbose_name入学时间) class Meta: db_table student ordering [student_no] # 默认按学号排序 verbose_name 学生信息 verbose_name_plural verbose_name def __str__(self): return f{self.student_no} - {self.name}字段类型选择上有几个关键点student_no用CharField而不是IntegerField因为学号虽然有数字特征但不会参与数学计算且可能有前导零gender用choices配合CharField在Django admin中会自动生成下拉框grade用ForeignKeyon_delete必须是必填参数这是Django 2.0以后的强制要求CASCADE表示班级删除时该班学生一并删除若改为SET_NULL则班级删除时学生保留但需要把grade字段设为nullTrue。3.2 makemigrations与migrate的完整流程模型定义完成后数据迁移是绕不开的一环。在项目根目录执行python manage.py makemigrations student python manage.py migrate student返回结果应该是类似“Migrations for student: ... Create model Grade ... Create model Student”的信息。第一句makemigrations的作用是生成0001_initial.py迁移文件它记录了模型的变化历史类似Git里的commit操作第二句migrate才是把变化同步到数据库。加上app名student可以缩小范围不加则对全项目所有app做检查。执行完迁移后可以用下面的命令反向确认表结构是否创建成功python manage.py sqlmigrate student 0001这条命令会打印出Django实际执行的SQL语句。课设答辩时老师问“ORM底层怎么映射的”直接把这个SQL输出拿出来讲说服力远高于背概念。比如Student表的SQL中会有“CREATE TABLE student (... FOREIGN KEY (grade_id) REFERENCES grade (id))”这就把models.py里的ForeignKey和数据库里的外键约束对应起来了。3.3 增删改查与“查询后删除对象”的常见坑热点词里出现的“django执行查询-删除对象”实际踩坑率非常高。直接看代码# 在django shell中演示python manage.py shell进入交互环境 from student.models import Student, Grade # 增创建一条数据 grade Grade.objects.create(name计算机2101, head_teacher王老师) student Student.objects.create( student_no2021001, name张三, genderM, age20, gradegrade ) # 查get与filter的区别 student_one Student.objects.get(pk1) # get返回单个对象查不到或查到多条都会抛异常DoesNotExist / MultipleObjectsReturned student_list Student.objects.filter(grade__name计算机2101) # filter返回QuerySet查不到返回空QuerySet不会抛异常 # 改批量更新 Student.objects.filter(grade__name计算机2101).update(age21) # 删删除单个对象 student_one.delete() # 返回的是 (1, {student.Student: 1}) # 删批量删除 Student.objects.filter(genderM).delete() # 条件删除先查询再删除适合删除前需要确认的场景 del_queryset Student.objects.filter(age__gt25) print(f即将删除 {del_queryset.count()} 条数据) del_queryset.delete()这里最容易踩的坑有三个。第一个是get与filter用混get只适合按唯一字段取一条记录比如学号、主键只要查不到直接抛DoesNotExist异常导致整个视图500。所以视图里推荐写法是Student.objects.filter(student_noxxx).first()返回None而不是抛异常。第二个坑是在用age__gt这种双下划线写法时字段名和操作符写反正确的是字段名 双下划线 操作符比如age__gt、created_at__lt、grade__name__contains。第三个坑是delete()方法只对QuerySet返回删除数量对模型实例返回None别指望它给你返回被删对象的信息。操作代码写法返回类型异常情况查询单条Model.objects.get(pk1)模型实例DoesNotExist / MultipleObjectsReturned条件查询Model.objects.filter(namex)QuerySet无空QuerySet取第一条Model.objects.filter().first()模型实例或None无更新单条instance.save()无无更新多条queryset.update(age21)受影响行数无删除单条instance.delete()tuple无这条表可以贴到答辩PPT里覆盖面比“只写一个增删改查流程”扎实得多。4. 视图、URL路由与模板渲染把学生数据变成页面4.1 URL配置文件的分层设计这个项目里路由是分两层的项目根路由DjangoStu/urls.py负责把URL分发给student这个appapp内部的urls.py负责具体页面的映射。这样的好处是当一个项目里有多个app学生管理、教师管理、课程管理时URL不会越堆越乱。# DjangoStu/urls.py from django.contrib import admin from django.urls import path, include urlpatterns [ path(admin/, admin.site.urls), path(, include(student.urls)), ] # student/urls.py from django.urls import path from . import views urlpatterns [ path(, views.student_list, namestudent_list), path(student/int:pk/, views.student_detail, namestudent_detail), path(student/add/, views.student_add, namestudent_add), path(student/int:pk/edit/, views.student_edit, namestudent_edit), path(student/int:pk/delete/, views.student_delete, namestudent_delete), ]int:pk是路径转换器意味着URL中该位置必须是个整数Django自动把值转换为int类型。这样就省去了自己从URL字符串里解析参数再转类型的步骤。name参数给URL起了别名模板里用{% url student_detail pkstudent.pk %}引用而不是硬编码URL字符串这样未来路由变了模板不用改。4.2 视图函数如何工作视图是“模型和模板之间的胶水”。看学生列表页的视图逻辑# student/views.py from django.shortcuts import render, get_object_or_404, redirect from django.contrib import messages from .models import Student from .forms import StudentForm def student_list(request): 渲染学生列表支持按姓名搜索和按班级筛选 students Student.objects.all().select_related(grade) search_keyword request.GET.get(keyword, ).strip() grade_id request.GET.get(grade, ) if search_keyword: # 双下划线语法name字段包含关键词 students students.filter(name__containssearch_keyword) if grade_id: students students.filter(grade_idgrade_id) # 按学号排序 students students.order_by(student_no) return render(request, student_list.html, { students: students, keyword: search_keyword, }) def student_detail(request, pk): 学生详情页 student get_object_or_404(Student, pkpk) return render(request, student_detail.html, {student: student}) def student_add(request): 新增学生 if request.method POST: form StudentForm(request.POST) if form.is_valid(): form.save() messages.success(request, 学生添加成功) return redirect(student_list) else: form StudentForm() return render(request, student_form.html, {form: form})这里有两个细节值得展开。select_related(grade)是个查询优化方法它会把关联的班级表通过SQL的JOIN一次性查出来不加这一句的话在模板里每访问一次student.grade.name都会额外发一条SQL查询100个学生就得多100条查询语句这就是N1查询问题。get_object_or_404包装了get的DoesNotExist异常查不到时直接返回404页面省去手写try捕获。request.method的判断是表单提交的标准写法GET请求时返回空表单让用户填写POST请求时校验数据并保存。messages.success是Django的消息框架保存成功后页面顶部会闪现一条成功提示。4.3 模板语法与静态资源挂载对应的模板文件在templates/student_list.html中!DOCTYPE html html head title学生信息列表/title link relstylesheet href{% static bootstrap/css/bootstrap.min.css %} link relstylesheet href{% static font-awesome/css/font-awesome.min.css %} /head body div classcontainer h2i classfa fa-users/i 学生信息列表/h2 form methodget classform-inline input typetext namekeyword value{{ keyword }} placeholder输入姓名搜索 button typesubmit classbtn btn-primary搜索/button /form table classtable table-bordered thead tr th学号/th th姓名/th th性别/th th班级/th th操作/th /tr /thead tbody {% for student in students %} tr td{{ student.student_no }}/td td{{ student.name }}/td td{{ student.get_gender_display }}/td td{{ student.grade.name }}/td td a href{% url student_detail pkstudent.pk %}详情/a a href{% url student_edit pkstudent.pk %}编辑/a /td /tr {% empty %} trtd colspan5暂无数据/td/tr {% endfor %} /tbody /table /div /body /html模板开头用{% static %}标签引用CSS资源但模板要正常工作需要在模板文件顶部加一行{% load static %}。项目正文里看到的ueditor.css、ueditor.min.css、video-js.css等静态文件都是放在static目录下被模板引用的。如果你发现页面样式丢失按三个方向排查一是模板里有没有{% load static %}二是settings.py里STATICFILES_DIRS路径是否指向了正确的static目录三是URL用/static/xxx直接访问看返回200还是404。模板中{{ student.get_gender_display }}是choices字段的配套方法student.gender在数据库里存的是M或F直接输出就是英文字母加上get_gender_display后显示的是中文“男/女”。这是课设里经常被忽略的细节。admin后台的注册在admin.py中# student/admin.py from django.contrib import admin from .models import Student, Grade admin.register(Student) class StudentAdmin(admin.ModelAdmin): list_display (student_no, name, gender, age, grade, phone) search_fields (student_no, name) list_filter (grade, gender) list_per_page 20 admin.register(Grade) class GradeAdmin(admin.ModelAdmin): list_display (name, head_teacher)这样在后台管理页面就多了“学生信息”和“班级”的增删改查入口不用自己写一个管理页面。admin站点美化通常从两个方向入手一个是给list_display增加字段让列表更完整另一个是引入django-simpleui这类第三方应用替换默认admin模板需求是“能看但不折腾”的话配置list_display和search_fields就够了。5. 部署到Linux服务器前的三个前置检查5.1 DEBUGFalse与静态文件的404问题本地用runserver跑没有任何问题一旦部署到云服务器首先撞见的就是静态文件404。原因在于runserver是Django自带的开发服务器会自动处理静态文件分发而生产环境下换用Gunicorn或uWSGI后Django默认不再处理静态文件这需要你手动把项目里的static目录收集到一个统一目录python manage.py collectstatic执行前在settings.py确认三行配置已就位DEBUG False ALLOWED_HOSTS [your_server_ip, www.yourdomain.com] STATIC_ROOT BASE_DIR / staticfilesDEBUG改False后原来的STATICFILES_DIRS仍然指向source目录而STATIC_ROOT是收集后的输出目录。没设置STATIC_ROOT就执行collectstatic会报“Youre using the staticfiles app without having set the STATIC_ROOT setting”。5.2 宝塔面板部署的两个坑如果服务器是宝塔面板部署方式一般是Nginx Gunicorn。宝塔的Python项目管理器里填入项目路径和Python版本一键创建Gunicorn的systemd服务。但有两个坑很容易忽略。第一个坑是Python版本的兼容性。宝塔默认安装的Python版本可能和项目requirements.txt里指定Django版本不匹配。Django 2.2支持Python 3.5到3.9Django 3.2支持Python 3.6到3.10你项目的requirements.txt里如果写着Django2.2.10服务器上装Python 3.10migrate时直接报错。检测命令是python --version pip show django | grep Version第二个坑是数据库编码。MySQL建库时默认可能是latin1或utf8mb3Django存储中文没问题但如果有Emoji字符存入会报“Incorrect string value”的错误。建库时明确指定UTF8MB4是标准做法CREATE DATABASE student_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;5.3 一个实用的验证脚本部署完成后光看“服务启动成功”不放心的话在项目根目录写一个临时脚本验证ORM、数据库连接和视图函数三者都正常python manage.py shell -c from student.models import Student from django.test import Client # 1. 验证数据库可读 count Student.objects.count() print(f学生总数: {count}) # 2. 验证页面可访问 client Client() resp client.get(/) print(f首页状态码: {resp.status_code}) # 3. 验证后台登录页 resp_admin client.get(/admin/) print(f后台状态码: {resp_admin.status_code}) 输出三行都应该正常。首页状态码200说明路由和视图没问题后台状态码200说明admin没报错。这个脚本打出的“学生总数”如果抛OperationalError那问题一定出在settings.py里DATABASES配置或MySQL用户权限上如果首页500而shell查询正常那就是模板或视图代码有问题配合tail -n 50 nohup.out看异常堆栈即可。这套流程走完后再遇到类似课程设计项目你就可以直接从models.py和settings.py入手而不是从头翻起——Django项目的核心就在配置与模型之间的对应关系里。本文还有配套的精品资源点击获取