ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Django校园网站毕设全流程指南:从模块设计到部署答辩

Django校园网站毕设全流程指南:从模块设计到部署答辩 毕业设计做校园网站选Django这个技术栈是我的优先推荐。别急着反驳先把话说完校园网站这个题目本质是“信息展示用户交互后台管理”三类需求的组合而Django天生就是为这类Web应用准备的。自带ORM、Admin后台、认证系统、模板引擎几乎把毕设里最耗时、最容易出错的底层工作全包了你只需要把精力放在业务设计和功能实现上。这篇文我按自己的实操经验把从零搭建一个多功能校园网站的完整流程、核心代码、踩坑点全写清楚给正在为毕设头秃的同学一份可以直接照着做的路线图。1. 项目定位与模块拆解1.1 为什么选Django做校园网站毕设先聊点实在的。很多同学的毕设选题是“校园网站”但拿到题目后第一反应是“这玩意不就是个静态页面吗”于是想用HTMLCSSJavaScript糊一个出来。这个思路在开题答辩时容易站得住等真到系统实现和论文撰写阶段就会非常被动——没有用户体系、没有数据持久化、没有后台管理论文里连“系统架构”和“数据库设计”两个章节都写不满。所以我的建议很直接校园网站必须做成动态Web应用而Django正是实现它的性价比之选。Django的几个特点几乎是为毕设量身定做的。第一MTV模式清晰Model-Template-View三层结构毕业论文里的“系统设计”章节直接按这个架构写逻辑通顺不用硬凑。第二自带Admin后台你不需要额外写管理端页面——这对毕设来说省掉的不是一两天的工作量而是一个完整的子系统。第三ORM简化数据库操作你甚至不需要写一行原生SQL数据表的增删改查全部用Python代码完成出错率低而且调试方便。安全性方面Django也替你想好了。XSS、CSRF、SQL注入这些常见的Web攻击框架本身就有防护机制论文里的“系统安全设计”部分可以直接引用这些特性来写不需要你自己造轮子。对一台普通笔记本就能跑起来的开发环境来说这个技术栈的负担也足够轻。1.2 “多功能”体现在哪儿模块设计清单既然题目叫“多功能校园网站”那这个“多功能”就不能只是花架子得是能落地的功能模块。我按自己的实际项目经验把校园网站最常见的功能拆成五个核心模块分别对应五个Django应用这样项目结构清晰论文也好写。第一个是用户模块对应账号注册、登录、个人资料管理这里我用Django自带的认证系统扩展不重复造轮子。第二个是新闻公告模块这是校园网站的门面包含校园新闻、通知公告、活动动态三类信息的发布和展示管理员从后台发布普通用户在前台浏览。第三个是课程模块包含课程信息展示、课程表查询、选课操作这个模块能体现网站的业务深度不是单纯的信息陈列。第四个是留言互动模块用户可以在线留言、评论、回复管理员进行审核和管理。第五个是社团模块展示社团列表、社团活动、成员招募信息算是给网站加一点校园文化气息。这套模块设计覆盖了信息发布、用户交互、业务管理三条线每一类都能在论文里单独成节工作量分布也比较均匀不会出现前面轻松后面赶工的情况。1.3 技术选型背后的理由技术选型这块我在项目里用的是Python 3.10 Django 4.2的组合。Python 3.10是在稳定性与第三方库兼容性之间比较平衡的版本支持f-string增强和模式匹配写代码时手感好Django 4.2是LTS长期支持版本官方保证安全修复到2026年比追最新的5.x版本更稳妥——毕设项目最重要的是能稳定跑完整个开发周期不用在开发途中为了兼容性问题花时间。数据库用的MySQL 8.0。可能有人问为什么不用Django默认的SQLite原因有两条一是SQLite的文件型数据库在并发写入场景下容易出锁问题等答辩演示时数据库一忙就会出现页面卡顿二是大部分学校数据库原理课程讲的是MySQL用MySQL做毕设从环境搭建到部署运维都能在论文里多写不少内容。但我也提醒一句本地开发时SQLite完全可以先顶着用等最后部署前再迁移到MySQL这个后文会细说。前端没有用前后端分离的方案而是用Django模板语言配合Bootstrap 5做服务端渲染。前后端分离对毕设来说不是必须的反而会引入跨域、接口文档、Token认证等一系列额外复杂度。用服务端渲染所有数据在服务端拼接好再返回给浏览器页面开发效率高调试也更直观。Bootstrap保证页面不至于太丑这对答辩印象分是有实质帮助的。2. 开发环境搭建与项目初始化2.1 Python虚拟环境与Django版本选择如果你还在用全局Python环境装包我建议你尽早改掉这个习惯。虚拟环境的核心价值是隔离不同项目的依赖版本——你电脑上可能同时有Django 3.2、4.2、5.x的项目不用虚拟环境就会互相冲突装一个包把另一个项目的运行环境搞崩是常事。创建虚拟环境的命令python -m venv venvLinux或macOS激活source venv/bin/activateWindows激活venv\Scripts\activate激活后命令行提示符前面会出现(venv)字样说明当前在虚拟环境内。然后安装Djangopip install django4.2.*为什么锁版本号这是我吃过亏才总结的教训。如果不锁版本pip install django会拉最新版等过两个月你照着某篇教程操作时发现命令不对查来查去才发现是新版API变了——而教程又不可能跟着每个版本更新。毕设周期内锁死一个LTS版本所有资料、第三方插件、论文截图都能对得上。2.2 创建项目与App分清项目与应用Django有个概念必须一开始就搞清楚项目project和应用app是两回事。项目是整个网站的容器里面放着全局配置应用是具体的功能模块每个应用负责一个业务域。一个项目可以挂多个应用一个应用也可以被多个项目复用。创建命令django-admin startproject campus_website cd campus_website python manage.py startapp users python manage.py startapp news python manage.py startapp courses python manage.py startapp messages python manage.py startapp clubs创建后项目结构是这样的campus_website/ manage.py campus_website/ __init__.py settings.py urls.py asgi.py wsgi.py users/ news/ courses/ messages/ clubs/我给每个app的命名都是复数形式这是Django社区的习惯模型类在Admin后台也显示更自然。项目名campus_website是Django默认的包名你完全可以改成别的但我不建议改——改名要连带改settings里的ROOT_URLCONF、WSGI_APPLICATION等一系列配置对新手来说没有收益只有风险。2.3 注册应用与配置基础信息创建完app之后最容易被忽略的是在settings.py里注册。不注册的话Django完全不知道这些应用的存在数据迁移、模板加载、Admin后台全部不会生效。settings.py里INSTALLED_APPS列表末尾添加INSTALLED_APPS [ # Django内置应用 django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, # 自定义应用 users, news, courses, messages, clubs, ]然后是三个基础配置中文界面、时区、静态文件路径。LANGUAGE_CODE zh-hans TIME_ZONE Asia/Shanghai USE_TZ True注意一个容易踩的坑USE_TZ True时Django在数据库里存的是UTC时间展示时才转换到本地时区。如果项目里有手动记录时间戳的地方最好用django.utils.timezone.now()而不是datetime.now()否则会出现数据库里时间和本地时间差8小时的问题。我的习惯是USE_TZ保持True所有时间域用Django的DateTimeField自动处理展示层通过模板过滤器转成当地时间。静态文件默认配置已经能用但建议在settings.py末尾加上一句避免DEBUG关闭后静态文件全部404STATIC_ROOT BASE_DIR / staticfiles这个等部署时有大用后面章节细讲。3. 核心数据模型设计3.1 用户模型扩展自定义User还是Profile用户模块是所有业务的基础。Django自带的User模型有用户名、密码、邮箱、姓名等常规字段但对校园网站来说不够——还需要学号、学院、专业、年级这类校园身份属性。这里有两种扩展方案我对比一下。方案一用Profile模型与User一对一关联。方案二直接自定义User模型继承AbstractUser。毕设项目我建议直接用方案二在users/models.py里写from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): student_id models.CharField(学号, max_length20, uniqueTrue, nullTrue, blankTrue) college models.CharField(学院, max_length50, blankTrue) major models.CharField(专业, max_length50, blankTrue) grade models.CharField(年级, max_length20, blankTrue) phone models.CharField(手机号, max_length11, blankTrue) avatar models.ImageField(头像, upload_toavatars/, nullTrue, blankTrue) class Meta: verbose_name 用户 verbose_name_plural 用户 def __str__(self): return self.username直接在users应用内定制User而不是用Profile方案核心原因是省心课堂上范例多数用OneToOneField扩展但每次取用户信息都要多一次关联查询而自定义User在请求的request.user里就能直接点出college和major。开发体验和运行效率都更好。然后必须修改settings.py告诉Django使用我们自定义的模型AUTH_USER_MODEL users.User关键提醒这个配置必须在首次执行makemigrations之前设置。如果先迁移了数据库再用自定义UserDjango会报错处理起来非常痛苦。开项目第一步就先改这个配置再走后续流程。3.2 新闻公告与课程数据模型新闻公告模块是校园网站的信息中枢需要设计分类字段来区分“通知公告”“校园新闻”“学术活动”等不同内容类型。我在news/models.py里的设计from django.db import models from django.utils import timezone class Category(models.Model): name models.CharField(分类名称, max_length50) slug models.SlugField(别名, max_length50, uniqueTrue) class Meta: verbose_name 新闻分类 verbose_name_plural 新闻分类 def __str__(self): return self.name class News(models.Model): title models.CharField(标题, max_length200) category models.ForeignKey(Category, on_deletemodels.CASCADE, verbose_name分类) cover models.ImageField(封面图, upload_tonews_covers/, nullTrue, blankTrue) content models.TextField(正文内容) author models.ForeignKey(users.User, on_deletemodels.CASCADE, verbose_name作者) views_count models.PositiveIntegerField(浏览数, default0) is_published models.BooleanField(是否发布, defaultFalse) created_at models.DateTimeField(发布时间, defaulttimezone.now) updated_at models.DateTimeField(更新时间, auto_nowTrue) class Meta: verbose_name 新闻公告 verbose_name_plural 新闻公告 ordering [-created_at] indexes [ models.Index(fields[-created_at]), ] def __str__(self): return self.titleis_published字段是给后台预留的发布开关管理员写好草稿不发布前台就看不到这个设计在论文的“系统功能设计”里能写出一小节。课程模块稍微复杂一点它要同时支撑“课程信息展示”和“选课操作”两种能力。我在courses/models.py里的设计class Course(models.Model): name models.CharField(课程名称, max_length100) code models.CharField(课程编号, max_length20, uniqueTrue) teacher models.CharField(授课教师, max_length50) credit models.DecimalField(学分, max_digits2, decimal_places1) capacity models.PositiveIntegerField(容量, default60) schedule models.CharField(上课时间, max_length100) location models.CharField(上课地点, max_length100) description models.TextField(课程简介, blankTrue) class Meta: verbose_name 课程 verbose_name_plural 课程 def __str__(self): return f{self.name}{self.code} class Enrollment(models.Model): student models.ForeignKey(users.User, on_deletemodels.CASCADE, verbose_name学生) course models.ForeignKey(Course, on_deletemodels.CASCADE, verbose_name课程) enrolled_at models.DateTimeField(选课时间, auto_now_addTrue) class Meta: verbose_name 选课记录 verbose_name_plural 选课记录 unique_together (student, course)选课记录用中间表Enrollment来做多对多关联而不是直接给Course加students ManyToManyField好处是可以在选课记录上挂选课时间、成绩、退选状态这些扩展字段。为了控制选课人数还要在后面的视图逻辑里做容量判断——数据模型里不防超员但业务逻辑上防这是服务端开发的通用思路。3.3 留言板与评论模型留言模块要有审核机制否则校园网站会变成垃圾信息池。我给留言和评论分别建表留言是用户对网站的反馈而评论是针对某条新闻的讨论它们场景不同不该混在一张表里。messages/models.pyclass Message(models.Model): STATUS_CHOICES ( (pending, 待审核), (approved, 已通过), (rejected, 已拒绝), ) user models.ForeignKey(users.User, on_deletemodels.CASCADE, verbose_name留言用户) content models.TextField(留言内容) status models.CharField(状态, max_length20, choicesSTATUS_CHOICES, defaultpending) reply models.TextField(管理员回复, blankTrue) created_at models.DateTimeField(留言时间, auto_now_addTrue) class Meta: verbose_name 留言 verbose_name_plural 留言 ordering [-created_at]评论需要挂在新闻上class Comment(models.Model): news models.ForeignKey(news.News, on_deletemodels.CASCADE, related_namecomments, verbose_name新闻) user models.ForeignKey(users.User, on_deletemodels.CASCADE, verbose_name评论用户) content models.TextField(评论内容) created_at models.DateTimeField(评论时间, auto_now_addTrue) class Meta: verbose_name 评论 verbose_name_plural 评论 ordering [created_at]related_namecomments这个参数特别实用设置后可以通过news_obj.comments.all()直接取到某条新闻的全部评论反向查询非常顺手不设置的话就要用comment_set这种难看的方法名。3.4 数据迁移的执行要点模型写完后执行迁移python manage.py makemigrations python manage.py migratemakemigrations是根据模型变化生成迁移文件migrate是把迁移应用到数据库。常见错误新写的字段没有给默认值Django会提示你选择方案新手容易卡在这一步。比如News模型里如果content忘了加blankTrue迁移时会问你要不要给已有数据补默认值——直接选“提供默认值”然后输入空字符串就行或者先加nullTrue, blankTrue再改模型设计。另外给个建议每完成一个子模块就做一次makemigrations和migrate不要攒到最后一次性迁移。小步提交的好处是出问题时容易定位——某次迁移出错直接回退到上一次干净的迁移文件就行而不会牵一发而动全身。4. 视图、路由与模板渲染4.1 路由设计从URL到视图URL是用户能直接感知到的部分设计得规范与否影响不小。我的思路是每个应用在项目根路由里挂一个前缀然后在应用内部自己管理子路径。项目根campus_website/urls.pyfrom django.contrib import admin from django.urls import path, include from django.conf import settings from django.conf.urls.static import static urlpatterns [ path(admin/, admin.site.urls), path(, include(news.urls)), path(users/, include(users.urls)), path(courses/, include(courses.urls)), path(messages/, include(messages.urls)), path(clubs/, include(clubs.urls)), ] if settings.DEBUG: urlpatterns static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)news/urls.py内部from django.urls import path from . import views urlpatterns [ path(, views.index, nameindex), path(news/int:pk/, views.news_detail, namenews_detail), path(category/slug:category_slug/, views.category_list, namecategory_list), ]Django 4.x的path函数用尖括号语法捕获URL参数int:pk表示匹配数字并传给视图不需要写正则表达式。命名为参数加上name后模板里可以直接写{% url news_detail news.pk %}即使URL规则调整模板代码也不需要跟着改这是维护性上很关键的设计。4.2 基于类的视图与通用视图视图层我用的是Django的通用视图搭配少量自定义逻辑。以首页新闻列表为例用ListView最省事from django.views.generic import ListView, DetailView from .models import News, Category class IndexView(ListView): model News template_name news/index.html context_object_name news_list paginate_by 10 def get_queryset(self): return News.objects.filter(is_publishedTrue).select_related(category, author)注意get_queryset里我用了select_related。这是一个经常被忽略、但影响很大的优化手段如果你在模板里循环访问news.category.name默认情况每循环一次就会执行一条SQL查询N条新闻就是N1条查询页面会明显变卡。用select_related把关联表一次性查出来查询次数直接降为1。我每次写完模板、发现页面响应变慢时第一反应就是检查有没有缺select_related——这是Django性能优化里性价比最高的一个动作。新闻详情页用DetailView同时加浏览数统计from django.views.generic import DetailView from django.db.models import F class NewsDetailView(DetailView): model News template_name news/detail.html context_object_name news def get_object(self, querysetNone): obj super().get_object(queryset) News.objects.filter(pkobj.pk).update(views_countF(views_count) 1) return obj用F(views_count) 1做计数器自增是一个数据库层面的原子操作。它把“读出当前值、加1、写回”三个步骤交给数据库原子性保证并发请求下也不会出现计数丢失比自己写obj.views_count 1; obj.save()安全得多。官网文档详细介绍了F表达式答辩时能说出这个点给老师的印象分是完全不一样的。选课视图需要用LoginRequiredMixin限制登录用户还要处理容量判断from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic import View from django.shortcuts import redirect from django.contrib import messages from .models import Course, Enrollment class EnrollView(LoginRequiredMixin, View): def post(self, request, course_id): course Course.objects.get(pkcourse_id) enrolled_count Enrollment.objects.filter(coursecourse).count() if enrolled_count course.capacity: messages.error(request, 该课程人数已满) return redirect(course_list) Enrollment.objects.get_or_create(studentrequest.user, coursecourse) messages.success(request, 选课成功) return redirect(my_courses)这里刻意用get_or_create而不是先查再建是因为它自带了并发去重逻辑——如果两个请求同时提交选同一门课先查再建方案可能出现两条重复记录而get_or_create在数据库存在唯一约束的情况下能保证幂等。课程表里unique_together在这里发挥了真正的作用它不只是约束数据更是在业务层帮你兜底。4.3 模板继承与页面美化模板这块Django的模板继承机制是提高复用性的利器能让所有页面共用一套布局不需要每个页面把头部、导航、脚部重复写一遍。基础模板templates/base.html的核心结构!DOCTYPE html html langzh-hans head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title{% block title %}校园网站{% endblock %}/title link hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.3.0/dist/css/bootstrap.min.css relstylesheet /head body nav classnavbar navbar-expand-lg navbar-dark bg-primary div classcontainer a classnavbar-brand href{% url index %}校园网站/a div classcollapse navbar-collapse ul classnavbar-nav ms-auto {% if user.is_authenticated %} li classnav-item span classnav-link你好{{ user.username }}/span /li li classnav-item a classnav-link href{% url logout %}退出/a /li {% else %} li classnav-item a classnav-link href{% url login %}登录/a /li li classnav-item a classnav-link href{% url register %}注册/a /li {% endif %} /ul /div /div /nav main classcontainer py-4 {% block content %}{% endblock %} /main /body /html子模板只需要用{% extends base.html %}继承基础布局再填{% block content %}里的内容即可。前端框架用Bootstrap 5它的栅格系统能保证页面在手机和电脑上都正常显示答辩时用投影仪播放也不会出现布局错乱的问题。表单验证可以用Django内置的forms或model forms渲染时给字段加classform-control就能获得Bootstrap样式# forms.py from django import forms from django.contrib.auth.models import User from django.contrib.auth.forms import UserCreationForm class RegisterForm(UserCreationForm): class Meta: model User fields (username, email, first_name)模板中使用form methodpost classneeds-validation {% csrf_token %} {{ form.as_p }} button typesubmit classbtn btn-primary提交/button /form{% csrf_token %}是Django的CSRF保护这个Token不能省否则POST请求会被拦截并报403错误——这个问题几乎每个Django新手都会遇到多数不是配置错了而是模板里漏了这一行。5. 后台管理让毕设加分的关键5.1 注册模型与列表定制Django Admin是很多人低估的宝藏。你不需要写任何前端页面只需在admin.py里注册模型系统就会自动为生成增删改查界面。对毕设项目来说这等于白送一个完整的管理员子系统。基础注册# news/admin.py from django.contrib import admin from .models import Category, News class NewsAdmin(admin.ModelAdmin): list_display (title, category, author, is_published, created_at) list_filter (category, is_published) search_fields (title, content) date_hierarchy created_at admin.site.register(Category) admin.site.register(News, NewsAdmin)list_display控制后台列表显示哪些字段list_filter在右侧生成筛选器比如按状态和分类过滤search_fields生成搜索框标题和正文都能搜date_hierarchy在顶部生成按日期逐级筛选的面包屑新闻量多时非常实用。给自定义User模型注册时由于继承了AbstractUser需要小心不要丢失原生的UserAdmin配置。最稳妥的做法是继承UserAdmin再注册# users/admin.py from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import User class CustomUserAdmin(UserAdmin): list_display (username, student_id, college, major, is_staff) list_filter (college, grade, is_staff, is_superuser) admin.site.register(User, CustomUserAdmin)继承UserAdmin的关键在于它内部预设了大量的表单布局和权限逻辑直接注册容易丢失密码重置等核心功能。这个细节我反复提醒过身边的人——后台登录后点进去发现没有密码管理多半就是直接admin.site.register(User)而没继承UserAdmin导致的。5.2 数据导入导出与批量操作Admin里还可以通过actions机制自定义批量操作。比如新闻模块可以加一个“批量发布”的操作选中多条新闻后一键设置is_publishedTruedef make_published(self, request, queryset): queryset.update(is_publishedTrue) self.message_user(request, f已发布 {queryset.count()} 条新闻) make_published.short_description 批量发布选中新闻再把操作挂到NewsAdmin.actionsclass NewsAdmin(admin.ModelAdmin): actions [make_published]如果论文里有“系统数据管理”章节这些定制操作能体现你对业务的理解深度而不只是会用默认功能。6. 常见问题与排查技巧实录这部分是我觉得全篇最有价值的章节全是实操中踩出来的经验一个一个列给你。6.1 时区问题为什么数据库存的时间和页面显示的不一样这是Django新手问得最多的坑。现象是管理后台发布新闻明明显示下午3点数据库里存的却是早上7点。原因就是前面提到的USE_TZTrueDjango在数据库统一存UTC时间展示时才转本地时间。解决方案是在模板里用{{ news.created_at|date:Y-m-d H:i:s }}过滤器Django会自动完成UTC到本地时区的转换。如果你在代码里手动用datetime.datetime.now()获取时间并塞进模型这个值不会经过时区转换就会造成8小时的混乱。统一用django.utils.timezone.now()是唯一不会出错的做法。6.2 静态文件404DEBUG关闭后样式全部丢失开发环境下一切正常一关DEBUG页面就变裸奔。原因是Django在开发服务器里负责静态文件服务生产环境则不关掉DEBUG这个服务就没了。我在项目里同时做了三件事解决第一步在settings.py里设置STATIC_ROOT第二步执行python manage.py collectstatic把各应用和第三方库的静态文件收拢到一个目录第三步部署时用Nginx直接代理这个目录的静态文件。如果不想折腾NginxDjango的whitenoise库可以帮你把静态文件服务完美地嵌入Web应用进程安装后在MIDDLEWARE列表里加一行whitenoise.middleware.WhiteNoiseMiddleware即可这是最快的解决方案。6.3 ORM查询中的N1问题前面提过select_related这里展开说。N1问题指的是你查了N条主表记录访问关联数据时又执行了N次查询总共N1次数据库查询。10条新闻变成11次查询还能忍300条新闻变成301次查询页面延迟就会肉眼可见。排查方法很简单把DEBUGTrue时页面底部Django调试工具栏里的SQL查询次数列出来看谁在疯狂查库。修复手段有两个select_related用于外键一对一prefetch_related用于多对多和反向关联。这两个方法用得好页面性能直接提升一个量级。6.4 MySQL连接配置与编码问题用MySQL时settings.py里的配置如下DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: campus_db, USER: root, PASSWORD: your_password, HOST: 127.0.0.1, PORT: 3306, OPTIONS: { charset: utf8mb4, }, } }记得charset一定要写utf8mb4否则中文会出现编码问题。MySQL 8.0默认字符集是utf8mb4但连接层不加这个参数也可能出现乱码建议直接写出来。另外需要安装mysqlclient或pymysql驱动。我用的是pymysql因为它纯Python实现安装方便。安装后在项目根campus_website/__init__.py里加入import pymysql pymysql.install_as_MySQLdb()这个兼容层是为了让Django的MySQL后端与pymysql协同工作。需要注意如果本地用SQLite开发这一段加了也不会生效不会报错但如果忘了加而在部署后没有安装pymysql服务启动时会立刻报错——所以部署前最好整体检查一遍依赖列表。6.5 登录跳转配置不当导致的一个隐蔽问题Django的LoginRequiredMixin在用户未登录时会把用户重定向到settings.LOGIN_URL默认是/accounts/login/。如果你的登录页URI是/users/login/不配置就会跳到一个不存在的页面。正确做法是LOGIN_URL /users/login/ LOGIN_REDIRECT_URL / LOGOUT_REDIRECT_URL /LOGIN_REDIRECT_URL是用户登录成功后默认跳转的页面如果你用的是Django内置的LoginView这个配置能省去自定义视图的麻烦。同理LOGOUT_REDIRECT_URL控制退出后的去向。这三个配置虽然只是三行但漏掉任何一个用户流程就会断裂。6.6 表单提交后表单内容丢失的排查描述一下这个场景用户填写一个很长很长的留言表单点提交后系统报错表单内容却全部清空了用户气得想骂人。这个问题的根源是——Django的表单在显示错误时会重新渲染表单对象但每个字段初始值都是空的如果模板用的是{{ form.as_p }}已经填的内容就全部丢了。解决方案很简单模型绑定表单即使用ModelForm并传instance参数或者在渲染时把用户提交的旧数据传回去form MessageForm(request.POST) if form.is_valid(): form.save() return redirect(success) # 渲染时form里就是request.POST的内容 return render(request, messages/create.html, {form: form})只要form是基于request.POST构造的重新渲染时各字段的值自然带回来了。很多初学者会犯的错误是form和request.POST各算各的导致表单内容丢失——记住一句话验证失败时别重建新表单要复用带有用户数据的那个表单实例。7. 毕业设计答辩前必须做的三件事7.1 准备一份干净的数据答辩演示时最容易翻车的不是程序逻辑而是数据库里没有数据或者数据一看就是随手敲的乱码。我在答辩前一周找了一批接近真实场景的数据新闻公告至少20条时间跨度覆盖最近三个月标题和内容写得像模像样课程信息10门以上选课记录若干条留言和评论也要有几条最好带上管理员回复。一个数据丰满的系统给答辩老师的直观感受是这个项目是真实跑过的不是临阵磨枪做出来的演示品。7.2 梳理一遍项目启动流程真到答辩现场你是从命令行启动服务器的。流程要练习到不用看笔记激活虚拟环境、启动开发服务器、打开浏览器、登录账号、进入后台发布一条新闻、去前台展示效果。时间控制在三分钟以内过程不能有停顿。另外把数据库备份命令记熟python manage.py dumpdata data_backup.json万一操作不当把数据破坏了一条loaddata就能恢复不用全程盯着调试台的报错记录干着急。7.3 部署到云服务器或本机开机自启如果你有阿里云、腾讯云这类云服务器部署一下印象分会显著提升。方法不讲了网上教程一搜一大把我推荐的方式是gunicorn Nginx Supervisor三个组件各司其职——gunicorn跑Django应用Nginx反向代理并托管静态文件Supervisor保证进程挂了自动拉起。Django的ALLOWED_HOSTS记得改成服务器IP或域名否则访问时会报“无效的HTTP_HOST”错误。没有云主机的话本地部署也够用。在笔记本上把DEBUGFalse、ALLOWED_HOSTS[*]设置好配合forever或者任务计划程序让服务开机自启答辩时你只需要打开笔记本电源网站自动在localhost上跑起来这种细节不会加多少分但会让老师觉得项目完成度很高。8. 写在最后的几点个人心得我从大二开始用Django做项目前后折腾过在线考试系统、社团管理平台、二手交易网站毕业设计做校园网站反而觉得是最舒服的一次——因为Django把所有“地基”活都包揽了我能把精力全部集中在业务逻辑和交互体验上。这里分享几点个人体会。第一毕设项目的核心价值在于“完整闭环”而不是“高级功能”。一个能注册登录、能发布信息、有后台管理、有数据交互的校园网站远远好过一个只有炫酷前端但没有真实业务逻辑的半成品。Django让你用最低的复杂度把闭环跑通这是它作为毕设技术栈最大的优势。第二做项目过程中把“为什么选这个方案”记录下来。答辩时老师最喜欢问的问题就是为什么用Django为什么用MySQL为什么自定义User模型你不需要回答得多么高深只要能把“因为什么、有什么好处、代价是什么”讲清楚就足够扎实。这篇文里所有关于方案选择的解释你都可以转化成答辩时的话术。第三遇到问题时逆着报错信息去查Django官方文档远比翻各种博客靠谱。Django官方文档对每个模块的说明都很完整也有中文版查问题时优先看它。你踩的坑99%都是别人踩过的文档里通常有明确的约定和示例。第四也是最重要的一条毕设不是一个人的战斗。把这篇文章里的代码和思路吃透然后动手敲出来哪怕每天只写一两个小时三周时间足够产出一个体面的完整项目。遇到卡住的时候去社区搜一搜或者直接看看源码里对应代码Django的源码写得非常清晰读它本身就是一次学习。校园网站这个题目看起来普通但它包含了一个完整Web系统必备的全部要素——用户、内容、业务、管理、交互。认真做完一个你对Web开发的理解会上升一个台阶这不是刷十个教程能比的。把基本功打扎实答辩时你的底气和自信老师是能真切感受到的。
返回列表