news 2026/9/2 21:42:44

基于Django的毕业设计实战:从项目搭建到部署上线的完整闭环

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Django的毕业设计实战:从项目搭建到部署上线的完整闭环


毕业设计常见痛点:从“能跑就行”到“能上线”

做毕设时,90% 的同学都踩过同一个坑:代码越写越像“意大利面”,一个views.py塞两千行,模板里嵌着 SQL,静态文件路径全靠../../static硬编码。答辩前夜,老师一句“能不能外网访问?”瞬间破防——本地python manage.py runserver跑得好好的,放到云服务器就 500 报错,日志里只有一行TemplateDoesNotExist

我去年带过的学弟小 A 就是典型:功能都齐,但一压测就崩,数据库没索引、密码明文存、CSRF 关着,连 DEBUG 都没关。评委老师一句话:“这系统你敢让真实用户注册吗?”直接问懵。

痛定思痛,我把自己做过的一个“校园二手书交易”项目拆成模板,整理出一条“能跑、能测、能上线”的闭环流程,今天全部公开,让你少掉头发,多拿高分。

Django vs Flask:毕设场景下的“偷懒”与“不偷懒”

选框架前,先问自己三个问题:

  1. 要不要后台管理?
  2. 要不要自带用户认证?
  3. 要不要一口气写完 80% 样板代码?

如果答案都是“要”,Django 就是最优解。Flask 确实轻,但“轻”意味着一切自己搭:权限、ORM、后台、迁移、分页……对毕设这种“时间紧、人手少、需求杂”的场景,Django 的 batteries-included 就是救命稻草。

一句话总结:Flask 适合想“造轮子”的人,Django 适合想“交作品”的人。

核心模块实现:把“业务”拆成“边界清晰的盒子”

下面以“二手书交易”为例,展示三个高频模块。代码全部可跑,注释写给未来的你。

1. 用户系统:继承 AbstractUser,一步到位

# users/models.py from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): """统一用户模型,后续可扩展手机号、微信openid等字段""" mobile = models.CharField(max_length=11, blank=True, verbose_name="手机号") avatar = models.ImageField(upload_to="avatar/%Y/%m", blank=True) class Meta: db_table = "users" verbose_name = "用户"
# users/views.py from rest_framework import generics, permissions from rest_framework_simplejwt.views import TokenObtainPairView from .serializers import RegisterSerializer class RegisterView(generics.CreateAPIView): """注册接口,只开放 POST,无需鉴权""" queryset = User.objects.all() serializer_class = RegisterSerializer permission_classes = [permissions.AllowAny]

注册序列化器里把密码写成write_only,再调用set_password做哈希,杜绝明文。

2. 数据模型:先画 ER 图,再写代码

# books/models.py from django.db import models from users.models import User class Book(models.Model): """书籍信息:冗余字段放这里,经常联合查询的字段建索引""" name = models.CharField(max_length=128, db_index=True, verbose_name="书名") price = models.DecimalField(max_digits=6, decimal_places=2) owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="books") status = models.PositiveSmallIntegerField( choices=((0, "在售"), (1, "已售"), (2, "下架")), default=0, db_index=True ) created_at = models.DateTimeField(auto_now_add=True) class Meta: indexes = [ models.Index(fields=["status", "-created_at"]), # 常用列表排序 ]

3. REST API:用 ViewSet 减少 70% 代码

# books/views.py from rest_framework import viewsets, filters from django_filters.rest_framework import DjangoFilterBackend from .models import Book from .serializers import BookSerializer from .permissions import IsOwnerOrReadOnly class BookViewSet(viewsets.ModelViewSet): """CRUD 全集,/books/ 自动映射 5 个路由""" queryset = Book.objects.select_related("owner").all() serializer_class = BookSerializer filter_backends = [DjangoFilterBackend, filters.OrderingFilter] filterset_fields = ["status"] ordering = ["-created_at"] def perform_create(self, serializer): serializer.save(owner=self.request.user) # 自动注入当前用户

权限模块单独放permissions.py,保持“胖模型、瘦视图”的 Clean Code 原则。

性能与安全:把“坑”提前埋平

  1. 防 CSRF:Django 默认开启,模板里只要{% csrf_token %}即可;DRF 用 JWT 后,把 CSRF 中间件对 API 豁免,只保护 admin。
  2. 防 SQL 注入:ORM 本身参数化查询,但原生 SQL 一定用params占位,别拼接。
  3. 密码哈希:set_password自动调用 PBKDF2,毕业设计不需要 bcrypt 也能过审。
  4. 敏感字段脱敏:用户手机号显示138****1234,序列化器里用SerializerMethodField处理。
  5. 查询优化:select_related外键、prefetch_related多对多,把 N+1 扼杀在本地。

压测 200 并发、2000 本书,优化前 QPS 43,优化后 312,服务器 1C2G 无压力。

部署流程:Gunicorn + Nginx + systemd 三板斧

  1. 云主机开 22/80/443 端口,系统用 Ubuntu 22.04。
  2. 建非 root 用户django,项目丢/home/django/bookstore
  3. 本地导出依赖:pip freeze > requirements.txt,服务器建 venv 后安装。
  4. 收集静态文件:
python manage.py collectstatic --noinput
  1. 配置 Gunicorn:
# gunicorn_conf.py bind = "127.0.0.1:8000" workers = 2 * CPU 核数 + 1 max_requests = 1000 max_requests_jitter = 100
  1. systemd 守护:
# /etc/systemd/system/gunicorn-bookstore.service [Unit] Description=gunicorn daemon for bookstore After=network.target [Service] User=django Group=django WorkingDirectory=/home/django/bookstore ExecStart=/home/django/venv/bin/gunicorn -c gunicorn_conf.py config.wsgi:application Restart=always [Install] WantedBy=multi-user.target
  1. Nginx 反向代理:
server { listen 80; server_name yourdomain.com; location /static/ { alias /home/django/bookstore/static/; } location /media/ { alias /home/django/bookstore/media/; } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; } }
  1. 开机自启:
sudo systemctl enable gunicorn-bookstore nginx

生产环境避坑指南:DEBUG=False 后世界变了

  • 静态文件 404:DEBUG=False 后 Django 不再代理静态,必须collectstatic并交给 Nginx。
  • 允许主机:别忘了ALLOWED_HOSTS = ["yourdomain.com"],否则 400 Bad Request。
  • 数据库迁移:先python manage.py migrate --check预检,再正式迁移;别手动改库结构。
  • 日志:建/var/log/django/目录,给django用户写权限,logging.dictConfig把 ERROR 级打到文件,方便排障。
  • 备份:写个cron每日pg_dumpmysqldump,丢到对象存储,毕业答辩前硬盘崩了也能救命。

下一步:把“能上线”升级成“可维护”

代码仓库里先拉一条logging分支,把关键路径加上logger.info();再写单元测试,用pytest-django覆盖注册、下单、下架三个核心流程。CI 用 GitHub Actions,每次 push 自动跑测试、测覆盖率 <80% 就亮红灯。

当你能把“日志 + 测试 + 监控”跑通,这份毕设就不再是“课程作业”,而是可以写进简历的“真实项目”。

动手吧,把你的views.py先拆成三个文件,再把 DEBUG 关掉,跑一遍collectstatic,最后把服务器重启。浏览器地址栏输入域名,看到首页正常加载那一刻,你会感谢今天没偷懒的自己。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 19:40:44

SiameseUIE中文信息抽取:医疗报告关键信息自动提取实战

SiameseUIE中文信息抽取&#xff1a;医疗报告关键信息自动提取实战 1. 为什么医疗信息抽取需要专用工具&#xff1f; 你有没有遇到过这样的场景&#xff1a;手头堆着上百份CT报告、病理诊断书和出院小结&#xff0c;每份都密密麻麻写满了专业术语——“肝右叶见2.3cm1.8cm低密…

作者头像 李华
网站建设 2026/8/25 17:31:45

DASD-4B-Thinking入门必看:Chainlit前端调用+vLLM后端服务完整链路

DASD-4B-Thinking入门必看&#xff1a;Chainlit前端调用vLLM后端服务完整链路 1. 为什么你需要了解DASD-4B-Thinking 你有没有遇到过这样的问题&#xff1a;写一段数学推导&#xff0c;模型总是跳步&#xff1b;生成一段Python代码&#xff0c;逻辑看似合理但运行就报错&…

作者头像 李华
网站建设 2026/8/24 13:16:18

大模型微调中的学习率艺术:从理论到实践的全景指南

大模型微调中的学习率艺术&#xff1a;从理论到实践的全景指南 当7B参数的大模型在微调阶段突然"失忆"&#xff0c;或是小数据集上loss曲线剧烈震荡时&#xff0c;算法工程师们往往会将目光投向那个看似简单却至关重要的超参数——学习率。这个控制参数更新步长的数…

作者头像 李华
网站建设 2026/8/25 22:21:30

无需专业知识:用ccmusic-database轻松识别音乐类型

无需专业知识&#xff1a;用ccmusic-database轻松识别音乐类型 你有没有过这样的经历&#xff1a;听到一段旋律特别抓耳的背景音乐&#xff0c;却完全说不上来它属于什么风格&#xff1f;是爵士、摇滚&#xff0c;还是某种融合流派&#xff1f;想给收藏的几百首无标签音频自动…

作者头像 李华
网站建设 2026/8/26 2:45:56

解析日期编码的复杂性

在日常的计算机编程中,处理日期和时间是一个常见却充满挑战的任务。特别是当涉及到从特定的字符串格式中解析日期时,情况会变得更加复杂。本文将通过一个实际的例子,探讨如何处理含糊不清的日期编码及其解决方案。 问题背景 假设我们有三个以字符串形式编码的日期: P_202…

作者头像 李华
网站建设 2026/8/24 3:50:17

造相-Z-Image惊艳效果:自然皮肤纹理、发丝级细节、柔和阴影动态演示

造相-Z-Image惊艳效果&#xff1a;自然皮肤纹理、发丝级细节、柔和阴影动态演示 1. 这不是“又一个文生图工具”&#xff0c;而是写实人像生成的新基准 你有没有试过用AI生成一张真正能用的人像照片&#xff1f;不是那种五官模糊、皮肤塑料感、光影生硬的“AI味”作品&#x…

作者头像 李华