ARTICLE DETAIL

资讯详情

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

Django毕业设计实战:旅游论坛从零部署到答辩

Django毕业设计实战:旅游论坛从零部署到答辩 简介这是一套面向计算机专业本科生的Django毕业设计实战项目聚焦旅游攻略分享与社区互动场景为学习Web全栈开发的学生提供可直接部署、二次开发的完整参考案例。资源包含341个文件涵盖90个Python后端逻辑文件、79个JavaScript交互脚本、45张JPG旅游图片素材、37个CSS样式文件及23个SVG图标资源整体压缩包12.84MB结构清晰模块化程度高便于理解MVT架构与前后端协同逻辑。已有220人学习下载适合Django初学者通过真实论坛系统掌握用户注册登录、图文攻略发布、多版块论坛管理、关注关系构建、邮箱/手机双验证绑定等核心功能实现。项目基于PyCharmDjango3.0Python3.7MySQL5.6环境开发附带完整数据库SQL脚本与Bootstrap/AOS/Font Awesome等主流前端库集成开箱即用是提升工程实践能力与毕设答辩竞争力的优质学习材料。1. 为什么一个旅游攻略论坛非得用 Django 而不是 Flask 或纯 HTMLJS你手头有个毕业设计任务做一个“旅游攻略论坛交流系统”要求能发帖、回帖、用户注册登录、按目的地分类、支持图片上传——不是静态页面是真能跑起来、老师能现场点开注册、发帖、删帖的完整系统。这时候翻开源码仓库一看满屏views.py、models.py、settings.py还有python manage.py runserver这种命令……很多人第一反应是“这玩意儿比写个 Vue 页面还重”但现实很骨感Django 不是“重”而是把毕业答辩最怕踩的坑——用户权限混乱、数据库字段改了前端崩、图片上传路径错乱、登录态一刷新就丢——全给你焊死在框架里。Flask 灵活没错但你要自己写用户认证中间件、自己配文件上传白名单、自己处理 CSRF 防跨站、自己写分页逻辑……而 Django 的User模型、ImageField、login_required、Paginator全是开箱即用的“防翻车组件”。PyCharm MySQL 组合也不是凑数——PyCharm 的 Django 支持能直接跳转到 model 字段定义、实时提示ForeignKey关联错误MySQL 则是唯一能把DateTimeField(auto_now_addTrue)和CASCADE外键约束稳稳落地的关系型数据库。这不是炫技是让一个没接触过生产级 Web 开发的学生在两周内交出一个不报 500 错误、不暴露 admin 后台、不被老师问倒“你怎么保证帖子删了评论也跟着删”的系统。适合谁适合需要可演示、可截图、可解释、可答辩的毕业设计者而不是想搞微服务架构的研究生。2. 从零建起用 PyCharm 创建 Django 项目并初始化 MySQL 数据库2.1 在 PyCharm 中创建 Django 项目别跳过这三步配置PyCharm 社区版或专业版均可专业版对 Django 支持更友好但社区版完全够用。新建项目时必须选择 “Django” 模板而非 “Pure Python”。PyCharm 会自动调用django-admin startproject并生成标准目录结构。关键配置在创建向导第二步Python interpreter务必选已安装的 Python 3.8 环境推荐 conda 或 venv不要用系统默认 PythonmacOS 自带的 Python 2.7 已淘汰Django version选4.2.xLTS 版本文档全、插件稳、兼容 PyCharm 2023More Settings → Application name填forum这是你的主 App 名后续所有业务逻辑放这里不是项目名。提示项目名如travel_forum和 App 名forum必须区分。项目名是根目录名App 名是INSTALLED_APPS里注册的模块名。混淆会导致python manage.py makemigrations找不到模型。创建完成后PyCharm 右侧会显示 Django 工具窗口Database、Django Console、Migrations。此时先别急着写代码——先配数据库。2.2 配置 MySQL不是只改settings.py还要验证连接通路Django 默认用 SQLite但毕业设计必须体现“真实数据库能力”所以切 MySQL。步骤分三块1本地 MySQL 环境确认确保已安装 MySQL 8.05.7 也可但注意密码加密方式差异。终端执行mysql -u root -p输入密码后进 MySQL 命令行执行CREATE DATABASE travel_forum DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER forum_userlocalhost IDENTIFIED BY StrongPass123!; GRANT ALL PRIVILEGES ON travel_forum.* TO forum_userlocalhost; FLUSH PRIVILEGES;注意utf8mb4是必须的否则用户发 emoji如 会报Incorrect string value错误。StrongPass123!是示例密码实际请按学校服务器要求设复杂度。2安装 PyMySQL 并配置settings.pyDjango 4.2 默认不支持 MySQLdb改用PyMySQL纯 Python 实现免编译pip install PyMySQL然后在项目根目录的__init__.py与manage.py同级中添加import pymysql pymysql.install_as_MySQLdb()再修改settings.py的DATABASESDATABASES { default: { ENGINE: django.db.backends.mysql, NAME: travel_forum, USER: forum_user, PASSWORD: StrongPass123!, HOST: 127.0.0.1, # 必须写 127.0.0.1不能写 localhostMySQL socket 问题 PORT: 3306, OPTIONS: { charset: utf8mb4, init_command: SET sql_modeSTRICT_TRANS_TABLES, }, } }参数说明HOST写127.0.0.1是血泪经验——Mac/Linux 下localhost会走 Unix socket而 PyMySQL 默认走 TCP导致Cant connect to local MySQL server错误init_command强制严格模式避免插入空字符串时静默失败。3PyCharm 内置数据库工具验证打开 PyCharm → View → Tool Windows → Database。点击→ Data Source → MySQL。填入Host:127.0.0.1Port:3306Database:travel_forumUser:forum_userPassword:StrongPass123!测试连接成功后右键travel_forum→Refresh应看到空数据库。这一步验证了 Django 能连上PyCharm 也能连上——双保险。2.3 创建核心模型旅游攻略论坛的 4 张表怎么设计才不翻车论坛核心实体就四个用户扩展 Django 自带 User、攻略帖、评论、分类标签。别自己重写 User 模型用AbstractUser继承扩展会更安全。在forum/models.py中from django.db import models from django.contrib.auth.models import AbstractUser from django.utils import timezone class CustomUser(AbstractUser): avatar models.ImageField(upload_toavatars/, blankTrue, nullTrue, verbose_name头像) bio models.TextField(max_length500, blankTrue, verbose_name个人简介) class Meta: verbose_name 用户 verbose_name_plural 用户 class Category(models.Model): name models.CharField(max_length50, uniqueTrue, verbose_name分类名称) description models.CharField(max_length200, blankTrue, verbose_name描述) def __str__(self): return self.name class Meta: verbose_name 分类 verbose_name_plural 分类 class Post(models.Model): title models.CharField(max_length200, verbose_name标题) content models.TextField(verbose_name正文) author models.ForeignKey(CustomUser, on_deletemodels.CASCADE, related_nameposts, verbose_name作者) category models.ForeignKey(Category, on_deletemodels.PROTECT, related_nameposts, verbose_name分类) # PROTECT 防删分类时误删帖子 created_at models.DateTimeField(defaulttimezone.now, verbose_name创建时间) updated_at models.DateTimeField(auto_nowTrue, verbose_name更新时间) is_published models.BooleanField(defaultTrue, verbose_name是否发布) # 草稿功能预留 def __str__(self): return self.title class Meta: verbose_name 攻略帖 verbose_name_plural 攻略帖 ordering [-created_at] # 默认按时间倒序 class Comment(models.Model): post models.ForeignKey(Post, on_deletemodels.CASCADE, related_namecomments, verbose_name所属帖子) author models.ForeignKey(CustomUser, on_deletemodels.CASCADE, related_namecomments, verbose_name评论者) content models.TextField(verbose_name评论内容) created_at models.DateTimeField(defaulttimezone.now, verbose_name评论时间) def __str__(self): return f{self.author.username} 评论 {self.post.title} class Meta: verbose_name 评论 verbose_name_plural 评论 ordering [created_at]关键设计理由CustomUser继承AbstractUser而非AbstractBaseUser前者保留username、email、password等全部认证字段只需加avatar和bio开发效率高Category的on_deletemodels.PROTECT防止管理员误删“日本”分类时所有日本游记帖子被级联删除毕业答辩时老师最爱问这个Post.created_at用defaulttimezone.now而非auto_now_addTrue后者在 model 初始化时赋值default在 save 时赋值更可控Comment的related_namecomments让post.comments.all()可以反查比post.comment_set.all()更语义化。执行迁移python manage.py makemigrations python manage.py migratePyCharm 的 Django 工具窗口会自动检测 migration 文件点击Migrate按钮也可同步执行。3. 用户认证与权限控制毕业设计里最常被问倒的三个权限问题3.1 用 Django 自带认证系统实现注册/登录/登出一行代码都不用写视图Django 的django.contrib.auth是毕业设计的“后悔药”。它提供/accounts/login/登录页可自定义模板/accounts/logout/登出GET 请求即可/accounts/password_change/密码修改/accounts/signup/注册需自己写 view但极简在forum/urls.py中from django.urls import path, include from django.contrib.auth import views as auth_views urlpatterns [ path(accounts/, include(django.contrib.auth.urls)), # 其他路由... ]然后在templates/registration/login.html中写登录表单PyCharm 会自动提示路径form methodpost {% csrf_token %} {{ form.as_p }} button typesubmit登录/button /form注意as_p会自动生成p标签包裹每个字段比手动写input更少出错{% csrf_token %}是必须的否则 POST 提交 403 Forbidden。注册页需自定义因为 Django 默认不提供。在forum/views.py中from django.shortcuts import render, redirect from django.contrib.auth.forms import UserCreationForm from django.contrib.auth import login def signup(request): if request.method POST: form UserCreationForm(request.POST) if form.is_valid(): user form.save() login(request, user) # 注册后自动登录 return redirect(home) # 跳转首页 else: form UserCreationForm() return render(request, registration/signup.html, {form: form})对应urls.py加path(accounts/signup/, views.signup, namesignup),3.2 权限控制为什么login_required比 session 判断更可靠学生常写if not request.session.get(user_id):判断登录但这是黑匣子——session 过期时间难控、CSRF 无防护、无法对接 Django Admin。正确做法是所有需要登录的视图加装饰器from django.contrib.auth.decorators import login_required login_required def create_post(request): # ...模板中用{% if user.is_authenticated %}控制按钮显示{% if user.is_authenticated %} a href{% url create_post %}发新帖/a {% else %} a href{% url login %}登录/a {% endif %}URL 重定向逻辑由LOGIN_URL控制在settings.py中设LOGIN_URL /accounts/login/ LOGOUT_REDIRECT_URL /这样未登录用户访问/post/create/会自动跳转到登录页登录后再回到原 URL——这是 Django 内置的next参数机制比手动存 session 可靠十倍。3.3 RBAC 权限分级毕业设计不需要复杂角色但要体现“管理员删帖”逻辑Django 的auth.Group和Permission是轻量级 RBAC。毕业设计只需两级普通用户能发帖、回帖、改自己帖子管理员能删任意帖子、封禁用户在admin.py中注册模型后进入/admin/创建 Group创建 Group 名为Moderator在 Permissions 中勾选forum | post | Can delete post、forum | comment | Can delete comment将指定用户加入该 Group。视图中判断from django.contrib.auth.decorators import user_passes_test def delete_post(request, post_id): post get_object_or_404(Post, idpost_id) if request.user.is_superuser or request.user.groups.filter(nameModerator).exists(): post.delete() return redirect(post_list) else: return HttpResponseForbidden(无权限删除)注意is_superuser是 Django 内置超级用户标志groups.filter(nameModerator).exists()是查用户是否在 Moderator 组。两者用or连接确保管理员和超级用户都能删。4. 帖子与评论功能落地从表单提交到图片上传的全流程闭环4.1 发帖表单ModelForm 是毕业设计的“防翻车神器”手写 HTML 表单易漏字段、类型错、验证弱。用ModelForm自动生成# forum/forms.py from django import forms from .models import Post, Category class PostForm(forms.ModelForm): class Meta: model Post fields [title, content, category, image] # image 字段需在 Post 模型中定义 widgets { content: forms.Textarea(attrs{rows: 6}), title: forms.TextInput(attrs{class: form-control}), }在Post模型中加image字段image models.ImageField(upload_toposts/, blankTrue, nullTrue, verbose_name封面图)视图中# forum/views.py from .forms import PostForm def create_post(request): if request.method POST: form PostForm(request.POST, request.FILES) # 注意文件必须传 request.FILES if form.is_valid(): post form.save(commitFalse) post.author request.user post.save() return redirect(post_detail, pkpost.pk) else: form PostForm() return render(request, forum/create_post.html, {form: form})模板create_post.htmlform methodpost enctypemultipart/form-data !-- 必须加 enctype -- {% csrf_token %} {{ form.as_p }} button typesubmit发布攻略/button /form关键点request.FILES是文件上传的必传参数enctypemultipart/form-data是 HTML 表单属性缺了文件根本传不到后端commitFalse先不保存以便手动赋author。4.2 图片上传路径与 Nginx 静态文件配置本地开发版Django 本地开发用django.contrib.staticfiles但图片属于MEDIA用户上传不是STATICCSS/JS。配置settings.pyimport os from pathlib import Path BASE_DIR Path(__file__).resolve().parent.parent.parent 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)这样http://127.0.0.1:8000/media/posts/xxx.jpg就能直接访问。注意MEDIA_ROOT是服务器上的绝对路径MEDIA_URL是 URL 前缀。static(...)只在DEBUGTrue时生效生产环境需用 Nginx 代理但毕业设计本地跑通即可。4.3 评论功能如何避免“评论后页面跳转丢失原帖”常见错误评论用普通 POST提交后跳转到/comment/success/用户找不到刚评论的帖子。正确做法是评论后重定向回原帖详情页# forum/views.py def add_comment(request, post_id): post get_object_or_404(Post, idpost_id) if request.method POST: content request.POST.get(content) if content.strip(): Comment.objects.create( postpost, authorrequest.user, contentcontent ) return redirect(post_detail, pkpost_id) # 关键重定向回当前 post模板中评论表单form methodpost {% csrf_token %} textarea namecontent required/textarea button typesubmit发表评论/button /form为什么不用 ModelForm因为评论字段极少只有 content手写更直观且get_object_or_404确保 post 存在避免Comment(post_id999)报错。5. 避坑指南毕业答辩前必须检查的 5 个致命错误5.1 现象运行python manage.py runserver报错ModuleNotFoundError: No module named mysqlclient原因Django 默认尝试加载mysqlclient但你装的是PyMySQL且没在__init__.py中执行pymysql.install_as_MySQLdb()。解决确认项目根目录与manage.py同级有__init__.py文件内容为import pymysql pymysql.install_as_MySQLdb()并确保该文件在manage.py执行时能被导入即不在子目录下。5.2 现象登录后访问/admin/显示 404或/accounts/login/提示TemplateDoesNotExist原因Django 的django.contrib.auth.urls依赖registration/login.html模板但你没在templates/registration/目录下创建该文件。解决在templates/registration/login.html中至少写form methodpost {% csrf_token %} {{ form.as_p }} button typesubmit登录/button /formPyCharm 会提示路径按提示创建目录即可。5.3 现象发帖时上传图片数据库存了posts/xxx.jpg但网页显示http://127.0.0.1:8000/media/posts/xxx.jpg404原因settings.py中MEDIA_ROOT路径错误或urls.py中没加static(settings.MEDIA_URL, ...)。解决检查MEDIA_ROOT os.path.join(BASE_DIR, media)——BASE_DIR必须指向项目根含manage.py的目录检查根urls.py是否有urlpatterns static(...)启动服务器后手动访问http://127.0.0.1:8000/media/应看到posts/目录否则路径错。5.4 现象Post.objects.filter(category__name日本)返回空但数据库里明明有数据原因MySQL 字符集不是utf8mb4导致中文匹配失败。解决进 MySQL 执行SHOW CREATE DATABASE travel_forum;确认字符集为utf8mb4若不是执行ALTER DATABASE travel_forum CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;重启 Django 服务。5.5 现象PyCharm 调试时断点不触发或print()不输出原因PyCharm 的 Django 运行配置未启用Debug模式或 Python 解释器路径不对。解决右上角运行配置 → Edit Configurations → Environment variables 中加PYTHONUNBUFFERED1Working directory 设为项目根目录含manage.pyScript path 设为manage.pyParameters 设为runserver --noreload--noreload避免多进程干扰调试。6. 毕业答辩加分技巧三个让老师眼前一亮的细节优化6.1 给管理后台加搜索与过滤3 行代码让老师觉得“这系统真能用”Django Admin 默认只显示__str__老师点开/admin/看到一堆Post object (1)会皱眉。在forum/admin.py中from django.contrib import admin from .models import Post, Comment, Category, CustomUser admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display [title, author, category, created_at, is_published] list_filter [category, is_published, created_at] # 右侧过滤栏 search_fields [title, content, author__username] # 顶部搜索框 date_hierarchy created_at # 按时间导航 admin.register(Comment) class CommentAdmin(admin.ModelAdmin): list_display [post, author, content, created_at] list_filter [post__category, created_at] search_fields [content, author__username, post__title]效果老师能在 Admin 页面用搜索框查“北海道”用右侧筛选器看“未发布”帖子用时间导航查上周数据——这比“后台能删数据”更有说服力。6.2 用django-crispy-forms让表单自动套 Bootstrap 样式免写 CSS毕业设计不必花时间写 CSS用crispy-forms一行搞定pip install django-crispy-formssettings.py中加INSTALLED_APPS [crispy_forms] CRISPY_TEMPLATE_PACK bootstrap4 # 或 bootstrap5模板中{% load crispy_forms_tags %} form methodpost {% csrf_token %} {{ form|crispy }} !-- 替换原来的 {{ form.as_p }} -- button typesubmit classbtn btn-primary提交/button /form效果表单自动有 Bootstrap 4 的栅格、圆角、悬停效果且响应式适配手机——老师用手机扫二维码看 demo 时不会觉得“这页面好丑”。6.3 生成初始数据用 fixtures 让答辩时一键还原“完美演示状态”每次答辩前手动在 Admin 里输 10 个用户、20 篇帖子太耗时。用 Django fixturespython manage.py dumpdata auth.Group forum.Category --indent2 fixtures/initial_data.json再创建fixtures/initial_users.json含测试用户然后在settings.py中FIXTURE_DIRS [BASE_DIR / fixtures]答辩前执行python manage.py flush --no-input # 清空数据库 python manage.py loaddata initial_data.json initial_users.json我的习惯在README.md里写明这三行命令答辩时当着老师面敲比口头解释“我做了很多测试数据”有力得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表