1. 项目设计与选型为什么是Django为什么是前后端分离“基于Django的多功能校园网站”这个标题几乎是计算机毕业设计里最经典的组合之一。每年都有大量学生选它但真正做出区分度、能拿优秀成绩的并不多。我刚带完几个毕设项目今天就把这个题目从选题逻辑、技术选型到代码实现、答辩准备完整拆一遍。先说选题逻辑。校园网站本身的需求非常明确用户注册登录、新闻通知、课程信息、失物招领、社团活动、论坛交流……这些功能贴近实际生活需求好理解评委一看就知道是真实场景不会问出“你这个系统解决了什么痛点”这种让人不好回答的问题。更重要的是这些模块天然适合拆分成“用户、内容、互动”三条线每一条线都能用上Django的核心能力——ORM、DRF、分页、搜索、权限控制做完全套下来技术栈的覆盖面足够论文也有东西可写。再说技术选型。为什么首选Django而不选Flask我跟很多学生说过一句话Flask适合做玩具Django适合做系统。这句话虽然绝对但对毕设来说很实用。毕设有明确的截止时间你的精力要优先花在“功能完整、逻辑正确、文档齐全”上而不是纠结“我这个路由该怎么组织、这个ORM要自己封装一层吗”。Django内置Admin后台、ORM、表单校验、认证体系、Session管理、迁移工具开箱即用能帮你省下大量时间。而且到答辩现场评委大概率会问“为什么用Django”这时候你可以答出“因为Django内置了完整的MVT架构和ORM开发效率高安全机制相对完善”远比“因为网上教程多”要体面得多。至于前后端分离这是当前Web开发的主流形态也是很多企业真实项目的架构。分离之后前端负责页面渲染和交互后端只提供JSON接口两边可以并行开发。校园网站在这个架构下还有一个额外的好处未来如果要出小程序或移动端App后端接口可以直接复用不用重写。这一点写到论文的“扩展性分析”里是很加分的论述。需要说明的是“前后端分离”不等于“不需要Django模板”。Django的模板引擎依然强大但在前后端分离模式下后端代码里基本只做接口返回不写HTML。常用的搭配是 Vue.js / React Element UI / Ant Design axios后端用Django Rest FrameworkDRF提供RESTful API。很多学生会纠结“我不会前端怎么办”实际上Vue的学习曲线比想象中平缓配合Element UI这种组件库做一个后台管理界面和前端展示页面不需要你会设计拖拖组件就能做出来。2. 核心技术与环境准备从零搭起项目的每一步2.1 环境与依赖版本选对了能少踩一半坑这一节很重要先说结论Django版本不要选最新选稳定版本。以当前生态来说Django 4.2 LTS是最稳妥的选择它修复了历史版本的大量问题同时兼容Python 3.10到3.12。别去追Django 5.x很多第三方库可能还没适配你在网上搜资料时也容易碰到版本不匹配的问题明明是照抄的代码跑起来却报错浪费了大量时间。具体安装流程我用的是这样的顺序python -m venv venv # 创建虚拟环境避免污染全局Python venv\Scripts\activate # Windows激活Linux/macOS用 source venv/bin/activate pip install django4.2.9 pip install djangorestframework3.14.0 pip install django-cors-headers4.3.1 pip install pymysql1.1.0 # 如果要用MySQL pip install pillow # 图片处理后面文件上传/头像功能必须 pip install djangorestframework-simplejwt5.3.0 # JWT认证我实测过的稳定组合是Python 3.11 Django 4.2.9 DRF 3.14 SimpleJWT 5.3。这个组合在网上能找到大量配套教程出问题时可以通过搜索快速解决这对毕设项目来说是极重要的考量。数据库的选择上如果只是毕设演示SQLite完全够用但考虑到很多学校推荐的数据库是MySQL这里建议直接用MySQL。毕设答辩环境里SQLite可能会出现一个尴尬的问题你拷了数据库文件过去文件路径变了导致打不开。MySQL就不会有这种问题。不过要注意MySQL 8.x默认的认证插件是caching_sha2_passwordPyMySQL对它的支持不如mysqlclient但如果你用PyMySQL 1.1.0以上版本配合Django 4.2基本不会出问题。另外务必配置一个.gitignore文件把venv目录和本地配置文件排除在外。你可能会觉得毕设又不需要协同开发但相信我答辩前你一定会改很多次代码有一个版本管理意识会让你少很多痛苦。哪怕不用Git至少把项目压缩包的命名加上日期比如campus_site_20250601.zip免得最终答辩时找不到“最新最终版”。2.2 创建Django项目目录结构的合理规划命令行先创建项目django-admin startproject campus_site cd campus_site python manage.py startapp users python manage.py startapp news python manage.py startapp courses python manage.py startapp lost_found python manage.py startapp forum很多学生拿到Django之后喜欢把所有功能塞进一个app里这其实是个坏习惯。校园网站虽然不算大型系统但按功能域拆分成多个app好处是显而易见的每个app只负责自己的数据模型和视图逻辑后期改动某一模块时不会牵动全局。如果出了Bug你也能更快锁定问题出现在哪个模块。创建完后的项目结构大概是这样campus_site/ ├── manage.py ├── campus_site/ # 项目配置目录 │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── users/ # 用户模块 ├── news/ # 新闻通知模块 ├── courses/ # 课程模块 ├── lost_found/ # 失物招领模块 └── forum/ # 论坛模块配置文件settings.py是重中之重需要修改的关键项包括INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, rest_framework, # DRF corsheaders, # 跨域配置 users, news, courses, lost_found, forum, ] MIDDLEWARE [ corsheaders.middleware.CorsMiddleware, # 位置放在前面 # ... 默认中间件 ] # 数据库配置MySQL DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: campus_site, USER: root, PASSWORD: 你的密码, HOST: 127.0.0.1, PORT: 3306, } } # 允许跨域 CORS_ALLOW_ALL_ORIGINS True # 开发环境先这样上线再收紧 CORS_ALLOW_CREDENTIALS True # JWT认证配置 REST_FRAMEWORK { DEFAULT_AUTHENTICATION_CLASSES: ( rest_framework_simplejwt.authentication.JWTAuthentication, ), }CORS_ALLOW_ALL_ORIGINS True只在开发阶段这么设。这是因为前后端分离下前端跑在localhost:8080后端跑在localhost:8000端口不同就触发了浏览器的同源策略如果不放开跨域限制你前端发过去的请求都会被浏览器拦下来。等部署到服务器之后建议把这个改成明确的允许域名列表比如CORS_ALLOWED_ORIGINS [https://yourdomain.com]。2.3 数据库建模把校园网站的核心表设计好Django的ORM允许你用Python类直接描述数据库表结构然后通过迁移命令生成真实的表。这种设计方式对学生来说非常友好因为你不必手写SQL而且Django会根据你的模型自动创建主外键关系。以多功能校园网站为例核心数据表至少包含这几张用户表users_user——扩展Django自带的AbstractUser增加学院、学号、手机号、头像等字段这样既能复用Django完备的用户认证逻辑又能存储校园业务所需的额外信息。新闻表news_article——标题、正文、封面图、发布人、发布时间、浏览量。这里要注意发布时间建议用auto_now_add让数据库自动写入创建时间前端展示时格式化好即可。课程表courses_course——课程名称、授课教师、上课地点、上课时间、学分、限选人数和已选人数。选课逻辑可以写成事务保证同一门课不会出现超选的情况。失物招领表lost_found_item——物品名称、物品图片、丢失/拾获地点、描述、联系方式、状态待认领/已找回。这个模块是“多功能”的加分项评委看到会眼前一亮因为很多学生的校园网站只做了新闻和课程缺少这种贴近生活的功能。论坛帖子表forum_post——标题、内容、发帖人、发布时间、点赞数、回复数。回复表可以单独建用外键关联到帖子。以下是用户表和新闻表的核心代码示例其余表的结构可以举一反三from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): student_id models.CharField(max_length20, uniqueTrue, nullTrue, blankTrue, verbose_name学号) college models.CharField(max_length50, nullTrue, blankTrue, verbose_name学院) phone models.CharField(max_length11, nullTrue, blankTrue, verbose_name手机号) avatar models.ImageField(upload_toavatars/, nullTrue, blankTrue, verbose_name头像) class Meta: db_table users_user verbose_name 用户 verbose_name_plural 用户 def __str__(self): return self.usernamefrom django.db import models from django.contrib.auth import get_user_model User get_user_model() class Article(models.Model): title models.CharField(max_length200, verbose_name标题) content models.TextField(verbose_name正文) cover models.ImageField(upload_tocovers/, nullTrue, blankTrue, verbose_name封面图) author models.ForeignKey(User, on_deletemodels.CASCADE, related_namearticles, verbose_name发布人) category models.CharField(max_length50, choices( (notice, 通知公告), (news, 校园新闻), (activity, 活动信息), ), defaultnews, verbose_name分类) views models.PositiveIntegerField(default0, verbose_name浏览量) created_at models.DateTimeField(auto_now_addTrue, verbose_name发布时间) class Meta: db_table news_article ordering [-created_at] verbose_name 新闻资讯 verbose_name_plural 新闻资讯 def __str__(self): return self.title这里想特别说一个细节新闻表的content字段用TextField还是用JSONField这取决于你的富文本方案。如果前端用的是wangEditor这类富文本编辑器它提交给后端的是带HTML标签的字符串那么TextField就够用。如果你希望正文以结构化方式存储那可以用JSONField。但建议直接用TextField因为简单可靠前端v-html渲染一下就是排版好的格式。3. 核心功能模块实现从登录认证到联调发布3.1 用户注册与JWT认证前后端分离下的会话保持前后端分离架构下传统的Session-Cookie方式很别扭前后端接口分离后不便维护登录状态。更主流的做法是用JWTJSON Web Token用户登录成功后后端返回一个加密的Token前端把它存在LocalStorage或Pinia/Vuex中之后每次请求都带着这个Token后端验证通过即放行。在Django中用SimpleJWT实现这个过程很顺。安装完成后视图代码只需要这样写from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView # urls.py 中注册 urlpatterns [ path(api/token/, TokenObtainPairView.as_view(), nametoken_obtain_pair), path(api/token/refresh/, TokenRefreshView.as_view(), nametoken_refresh), ]这样前端就能通过POST请求/api/token/把用户名密码拿过去换取一对令牌access和refresh。access的有效期建议设置为2小时refresh设置为7天。为什么不用单个长有效期Token因为一旦泄露长时间有效会让别人可以一直冒用你的身份。所以主流做法是短token搭配长refresh快过期时前端自动刷新用户无感知。有同学问过SimpleJWT默认的username/password登录不够用我想支持学号登录怎么做可以自定义一个TokenObtainPairSerializer然后改造视图类。这个属于进阶操作有基础的同学可以试一下。注册接口我用DRF的序列化器来实现关键代码如下from rest_framework import serializers from .models import User class RegisterSerializer(serializers.ModelSerializer): password serializers.CharField(write_onlyTrue, min_length6, error_messages{min_length: 密码长度不能少于6位}) class Meta: model User fields [id, username, password, student_id, college, phone] def create(self, validated_data): password validated_data.pop(password) user User(**validated_data) user.set_password(password) # 对密码做哈希加密绝不能存明文 user.save() return user注意create方法里用了set_password()这是Django对密码加密的标准方式默认使用PBKDF2算法。很多毕设项目这里容易犯一个错直接把前端传上来的password赋值给user导致密码明文存进数据库。答辩时如果评委点开数据库看到明文密码那基本就告别高分了。哪怕你自己不在意安全答辩老师不可能不在意。3.2 新闻通知模块接口分页、搜索与浏览计数新闻列表、搜索、详情是校园网站的门面功能。这里展现的技术点主要有三个第一ListView视图的分页。Django Rest Framework自带分页机制配置一下settings就能用REST_FRAMEWORK { DEFAULT_PAGINATION_CLASS: rest_framework.pagination.PageNumberPagination, PAGE_SIZE: 10, }前端传?page1、?page2后端返回的数据结构里会带count总条数和next、previous链接前端只要解析这组JSON渲染分页组件即可。第二搜索结果。可以用Django的Q对象实现模糊搜索from django.db.models import Q from rest_framework.views import APIView class ArticleListView(APIView): def get(self, request): keyword request.query_params.get(search, ) category request.query_params.get(category, ) articles Article.objects.all() if keyword: articles articles.filter( Q(title__icontainskeyword) | Q(content__icontainskeyword) ) if category: articles articles.filter(categorycategory) # 之后交给分页器处理icontains会生成LIKE查询这样标题中包含关键词的文章就能被搜到。第三浏览量的累加。这里有个容易被忽略的细节浏览量应该“点击详情时1”还是在列表页就不加正确做法是详情接口中修改但如果每次打开详情都加用户可以刷页面刷出高浏览量看起来就很假。我建议限制为每个用户对同一篇文章的多次访问在一定时间段内只计一次。简单实现就是用一个decorator通过session判断。不过为了简单我用了这样一个思路from django.utils import timezone from datetime import timedelta def record_view(request, article_id): key farticle_viewed_{article_id} last_view request.session.get(key) if not last_view or (timezone.now() - datetime.fromisoformat(last_view)) timedelta(hours2): Article.objects.filter(idarticle_id).update(viewsF(views) 1) request.session[key] timezone.now().isoformat()3.3 选课模块事务与并发限制选课功能是校园网站里最有“技术含量”的模块之一也是论文里可以重点展开描写的地方。先看核心代码from django.db import transaction from django.db.models import F transaction.atomic def select_course(request, course_id): course Course.objects.select_for_update().get(idcourse_id) if course.selected_count course.max_students: return Response({error: 该课程已满员}, status400) Selection.objects.create(userrequest.user, coursecourse) Course.objects.filter(idcourse_id).update(selected_countF(selected_count) 1) return Response({success: True})这段代码有几个要点用select_for_update()锁定该行记录防止两个用户同时看到剩余名额为1而同时抢课。如果用先查询再判断最后更新的普通方式并发量大时会出现超选。毕设虽然压测量不大但写对事务逻辑答辩时评委可能会揪着并发场景问。用F(selected_count) 1做原子更新这能保证“读取-计算-再写入”三个步骤不会被并发操作打断。如果用read-then-write方式偶数并发时结果可能出问题。选课记录表和课程表之间要有唯一约束保证一个学生对同一门课只选一次。可以在Selection模型的Meta里加unique_together [user, course]。3.4 失物招领与论坛模块文件上传和嵌套评论失物招领模块是典型的“图片基础字段”场景。图片上传需要配置MEDIA路径# settings.py MEDIA_URL /media/ MEDIA_ROOT os.path.join(BASE_DIR, media) # 主urls.py from django.conf import settings from django.conf.urls.static import static urlpatterns static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)上传的图片会存在media目录下访问url是/media/lost_items/xxx.jpg。这里务必注意一个问题开发环境下Django能自己处理media文件但如果部署到生产服务器媒体文件必须交给Nginx等服务器来处理Django不适合扛静态资源。写论文的部署章节时这一点要说明白否则导师会认为你对部署链路理解太浅。论坛模块可以做回复功能。一种简单的方法是建Post和Comment两张表Comment通过外键关联Post和User。前端展示时一次性取出该帖子所有的回复在前端按时间线渲染。如果非要做楼中楼建议用parent字段做自关联渲染时前端做递归展示不要在后端写复杂递归。3.5 实时推送与WebSocket让校园网站“活”起来如果你想让校园网站更出彩可以在新闻发布模块中加入WebSocket实时推送。比如管理员发布了一条紧急通知前端页面不需要刷新就能收到提示。Django生态里Django Channels是WebSocket的标准实现它能让Django像处理HTTP请求一样处理WebSocket协议。具体实现流程是pip install channels pip install channels-redis然后在settings.py里加上channels的配置把ASGI_APPLICATION指向你的路由文件。当你通过Admin或后台发布新闻时在save方法中发送一个channel_layer消息前端通过WebSocket订阅这个频道收到消息后弹出提示。这里有一种特殊情况——官方发布新闻后如何推送给在线用户Django Channels的group_send机制允许你按分组广播。你可以把所有在线用户都加入一个news_group发布时group_send一下前端就能收到实时通知。这个功能对“多功能”这个词的含金量加成很大也适合写成论文的“系统亮点”章节。当然这个功能在中大型项目中才有明显体验提升如果你的毕设时间紧张可以不做WebSocket但如果你做完基础模块还有富余时间强烈建议加上答辩效果会比单纯CRUD好不少。4. 前后端联调与常见问题排查实录4.1 跨域问题的完整排查思路前后端分离项目十个有九个第一次联调都挂在跨域上。现象是前端axios请求一直报错浏览器控制台显示CORS policy或者干脆请求都是404。排查步骤是这样的第一确认后端CORS中间件已安装且环境正确。django-cors-headers装好后中间件必须放在MIDDLEWARE列表里且尽量靠前。第二确认CORS_ALLOW_ALL_ORIGINS True在开发环境设置。但注意如果你同时设置了CORS_ALLOW_CREDENTIALS True某些版本的django-cors-headers会强制要求你不能用ALLOW_ALL_ORIGINS必须指定具体域名。这可能产生一个很隐蔽的坑前端明明配置了withCredentials却发现跨域还是失败。第三区分“预检请求”和“实际请求”。当你的请求不是简单的GET/POST且携带了自定义Header如Authorization时浏览器会先发一个OPTIONS请求后端要能正确响应这个OPTIONS。django-cors-headers会自动帮你处理OPTIONS请求但如果你的URL配置对这个路径没有匹配OPTIONS请求也会404从而卡住后续请求。所以我常建议前端统一封装axios都走一个api实例baseURL指向后端地址。这样后续如果要调整线上接口地址只改一处就行。封装代码大概是import axios from axios const api axios.create({ baseURL: http://127.0.0.1:8000/api, timeout: 5000, }) api.interceptors.request.use(config { const token localStorage.getItem(access) if (token) { config.headers.Authorization Bearer ${token} } return config }) export default api4.2 查询性能与N1问题校园网站数据量不大但答辩时如果你的新闻列表页很慢会非常拉低印象分。出现这个问题的常见原因就是N1查询。比如新闻列表页面展示作者名称时如果这样写articles Article.objects.all()随后序列化器里每次取article.author.username就会对每一条新闻都执行一次作者表的查询。看起来代码很干净实际上每查10条新闻Django总共会执行11条SQL。解决办法是使用select_related它会通过JOIN把外键字段一并查出来articles Article.objects.select_related(author).all()课程模块如果有外键指向教师表同理也用select_related。这个优化对几百条数据来说可能感觉不明显但评委一旦问你“这个查询有没有性能隐患”你答出“我用select_related做了预加载避免N1查询”你的技术深度分就上去了。4.3 数据库迁移问题改models不生效怎么办开发过程中你大概率会频繁修改models字段比如加了学院字段又删除一个联系方式字段然后python manage.py migrate报错提示Column xxx doesnt exist。这个问题的根源是你删除了某个模型里的字段但数据库中还有对应的列Django的迁移系统没法自动帮你删干净。我给你的建议是尽量把表结构一次设计到位后面主要通过新增字段来演进少删字段。如果确实要恢复可以执行以下命令重置app的迁移python manage.py migrate users zero python manage.py makemigrations users python manage.py migrate这个操作会把这个app的所有表删掉重建数据会丢所以只适用于开发阶段。如果你的数据已经测试过就不建议这样做了宁可写一个数据迁移脚本也不要去重置。4.4 文件上传踩坑图片不显示或访问404这个问题在失物招领模块里最容易出现。前台上传图片后img标签的src是/media/xxx.jpg但浏览器显示404。排查步骤是先看media目录下文件是否存在如果存在说明上传成功问题出在静态文件服务。开发环境下服务器需要配置好MEDIA_URL访问映射。如果你用的是python manage.py runserver默认会自动处理但如果你的前端是独立跑在Vite的8080端口那么你访问的路径是http://localhost:8080/media/xxx.jpgVite服务器根本没有这个文件自然404。正确的做法是前端img标签的src直接指向后端域名也就是http://localhost:8000/media/xxx.jpg而不是相对路径。4.5 前后端联调时的时间格式化问题Django默认的DateTimeField返回给前端时是这样的格式2025-06-01T10:30:00.123456Z。前端直接用new Date()解析没问题但Element UI的日期组件显示时默认要的是yyyy-MM-dd格式。不同前端页面处理时间格式的方式五花八门有的用dayjs有的用自定义函数很容易出现“详情页时间格式和列表页时间格式不一致”这种细节错误。建议后端的序列化器里统一返回格式化后的时间字符串专门写一个处理时间的序列化方法class ArticleSerializer(serializers.ModelSerializer): created_at serializers.DateTimeField(format%Y-%m-%d %H:%M:%S) # ...这样所有时间都长成一个样避免前端自我发挥。4.6 前端的token过期刷新与状态保持JWT模式的一个常见问题access token过期后用户可能还停留在页面上点击某个按钮时突然收到401错误然后整个页面就“卡死”了。比较好的做法是在axios响应拦截器里统一处理401api.interceptors.response.use( response response, error { if (error.response error.response.status 401) { return refreshToken().then(() { error.config.headers.Authorization Bearer ${newToken} return api(error.config) }) } return Promise.reject(error) } )简单写法是401时调用refresh接口拿new_token然后重新发送刚才失败的请求。如果refresh也失败就清除本地token并跳回登录页。这一步做到位答辩时前端交互体验很加分。5. 部署上线、文档写作与答辩准备的完整建议5.1 经典部署链路nginx uwsgi/asgi mysql毕设验收通常要求“能跑”但如果你能把项目真正上线到服务器那答辩效果完全是另一个层级。最经典的部署链路是第一步在服务器上装好Python环境拉代码进目录用虚拟环境装依赖。第二步用uWSGI或Gunicorn跑Django后端。uWSGI配置一个campus.ini[uwsgi] chdir /path/to/campus_site module campus_site.wsgi:application master true processes 4 socket /tmp/campus_site.sock chmod-socket 664 vacuum true这里用的是socket文件而不是端口这是为了和Nginx配合。Nginx的用户必须有权限访问这个sock文件否则会报502。很多时候学生部署失败就是因为忘了chmod-socket 664。第三步Nginx做反向代理和静态资源服务server { listen 80; server_name 你的域名或IP; location /api { include uwsgi_params; uwsgi_pass unix:///tmp/campus_site.sock; } location /media { alias /path/to/campus_site/media; } location / { root /path/to/dist; try_files $uri $uri/ /index.html; } }这里有一个关键点/location /是前端静态文件目录也就是你Vue项目build之后生成的dist目录。如果你没有单独部署前端想快速演示也可以把dist目录放到这里直接让Nginx托管这样前后端共享同一个80端口跨域问题在正式环境里也就顺带解决了。如果你用了前面提到的Django Channels做WebSocket那么还需要在Nginx的配置里加上对WebSocket升级协议的支持location /ws/ { proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; }5.2 文档报告与源码注释毕设评分的隐藏大头很多学生对源码和文档的态度是“能交就行”但毕设评分里论文/文档占比通常能达到50%以上这个比例是很多人不知道的。代码写得再好文档一塌糊涂分数一样上不去。Django项目的论文大纲大致是摘要 → 绪论背景、意义、国内外现状 → 相关技术介绍Django、Rest Framework、Vue、MySQL、前后端分离概念 → 系统需求分析用例图、功能需求、非功能需求 → 系统设计架构图、ER图、功能模块划分 → 系统实现每个模块的截图核心代码片段说明 → 系统测试测试用例表结果分析 → 总结与展望。代码注释上建议重点类和方法写docstring比如def create(self, validated_data): 创建用户使用set_password对密码进行哈希加密不保存明文这样的注释既能让评委快速读懂你的代码也能在代码讲解环节直接引用。不要写一堆没意义的注释什么“# 定义一个变量”这种反而拉低印象分。还有一点容易被忽视README文件。在项目根目录写一个条理清晰的README包括运行前需要改哪些配置、数据库初始化方式、账号密码、运行命令这样答辩时换一台电脑也能快速启动项目。如果评委看到你连README都没有连打开项目都不知道怎么操作那体验会很差。5.3 答辩准备被追问时如何不慌张答辩时评委最爱追问的问题我总结了高频的几个提前准备好就能从容应对为什么用Django而不用Spring Boot——Django生态成熟内置ORM和Admin对Python开发者友好开发效率高适合中小型Web系统的快速交付。什么是前后端分离它和传统MVC模式有什么区别——前后端分离指后端只提供API前端负责页面渲染与交互通过JSON进行数据交互。职责清晰、并行开发、易于扩展多端。Token和Session有什么区别JWT的优势是什么——Session存储在服务端需要扩展存储JWT是无状态的用户认证信息在Token中自带适合分布式部署。但JWT也有无法立即注销的缺点所以设置了较短有效期。数据库表结构为什么这么设计有没有考虑索引——你的news表可以按created_at建索引users表按student_id建唯一索引。答出这一点能证明你考虑了查询效率。你的系统如何保证数据安全——用户密码哈希存储、JWT过期机制、后端接口权限校验、前端路由守卫这几个点可以展开讲。如果评委让你现场改一个功能比如“把新闻列表改成按点击量排序”你只要在视图里改一行Order_by(-views)就行事先想想这类改动可能会考哪些提前在代码里留活口临场就不会慌。5.4 这个题目的后续扩展让毕设价值最大化多功能校园网站做完之后想要继续扩展的方向不少。首先是移动端适配因为很多学生都在校园里用手机访问题库或选课系统你可以做一个H5响应式版本或干脆用uni-app打包成小程序。后端接口已经是RESTful的前端换一个壳就能复用。其次是消息中心功能把失物招领的认领通知、课程表变动提醒汇总到站内信。还可以接入邮箱验证码或短信验证码提升注册校验的安全度。如果学有余力可以把数据统计做成可视化大屏用ECharts展示新闻发布趋势、选课热度等这类图放论文里非常抓眼球。我个人在实际操作中体会最深的一点是毕设项目的价值不在于惊艳的技术堆砌而在于你能把一条完整的业务链路做闭环。用户注册、发布内容、权限控制、异常处理、部署上线每一环都亲身趟过一遍这个收获比论文分数本身重要得多。哪怕过程中踩坑无数这些坑才是你答辩时能从容回答问题的底气。最后再分享一个小技巧开题之后第一时间去把数据库表和接口定义清楚拿给导师看一眼确认没问题再开始写代码。很多学生闷头写了一两周最后发现模块设计和导师预期完全不符。前期多沟通五分钟后期就能省五个晚上。这个题目本身不难难的是做得完整、做得扎实。只要你把基础功能做稳再加一个像失物招领、选课事务、WebSocket推送这样的亮点评分自然会有明显优势。
阅读完成 · 觉得有帮助?