news 2026/6/8 14:35:44

基于Django 3/4的轻量个人博客源码(含SQLite数据库与完整前后端)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Django 3/4的轻量个人博客源码(含SQLite数据库与完整前后端)

本文还有配套的精品资源,点击获取

简介:开箱即用的Django个人博客系统,适配本科Python毕业设计或自学实践。使用SQLite作为默认数据库,无需额外配置,执行python manage.py runserver即可本地运行。支持用户注册登录、密码修改、头像上传(user_logo目录)、文章发布与编辑(addArticle.html/upArticle.html/chageArticle.html)、分类展示(subject.html)、评论提交(comment_put.html)、个人主页(userinfo.html/userArticle.html)及后台管理(ArticleAdmin.html)。前端采用语义化HTML+CSS结构,统一继承base.html布局,包含首页(index.html)、文章详情页(showArticle.html)、修改资料页(upPwd.html)等10+模板页面;后端涵盖models.py(用户/文章/分类模型)、views.py(业务逻辑)、forms.py(表单验证)、urls.py(路由映射)、admin.py(后台集成)及完整migrations迁移文件。附带README.md说明文档、db.sqlite3预置数据库、uploads附件存储路径和.gitignore规范配置,代码模块清晰、注释完整,已通过实际部署与答辩验证。

1. 项目概述:为什么这套Django博客值得你花30分钟认真读完

我带过六届本科毕设,每年都有至少12个学生卡在“毕设系统做不出来”这道坎上——不是不会写代码,而是陷在环境配置、路由跳转404、表单提交没反应、数据库迁移报错、静态文件不加载这些“看不见的坑”里,最后两周通宵改PPT,答辩时连后台管理界面都不敢点开演示。直到2021年我把这套轻量博客源码整理出来,作为模板发给学生,连续三年,用它做毕设的同学100%一次性通过答辩,平均答辩时间缩短40%,提问环节几乎没人问“这个怎么实现的”,因为所有关键路径都跑得通、看得见、改得动。

它不是炫技型项目,没有React前端、没有Docker编排、不接Redis缓存、不搞JWT鉴权——它就老老实实跑在Django原生框架上,用SQLite当数据库,靠python manage.py runserver一条命令启动,连pip install都只要装Django一个包。关键词里写的“Django博客”“Python毕业设计”“SQLite个人博客”,每一个都不是虚的:Django博客,意味着它完整覆盖了Web开发最核心的MVT三层结构,models定义数据关系,views处理业务流转,templates渲染用户界面,每层之间怎么传参、怎么校验、怎么跳转,全在代码里明明白白;Python毕业设计,意味着它经得起答辩老师翻源码——models.py里每个字段类型都带verbose_name中文注释,views.py里每个函数开头都有三引号文档说明用途和参数,forms.py里每个表单字段都做了clean_XXX自定义校验逻辑,连admin.py里都配好了list_display和search_fields;SQLite个人博客,是它最硬核的实用主义选择:不需要你装MySQL、不用记root密码、不担心端口冲突,db.sqlite3文件直接放在项目根目录,第一次运行自动建库建表,删掉重来只要删这个文件+清空migrations文件夹,比重启电脑还快。

我见过太多学生为了“显得高级”,硬上PostgreSQL却连pg_config都装不对,或者执着于Bootstrap美化页面,结果首页CSS加载失败导致整个导航栏消失,答辩时手忙脚乱查console报错。这套源码反其道而行之:前端用纯语义化HTML+基础CSS,base.html里用{% block content %}统一占位,所有子页面只填内容不碰布局;后端路由全部用path()函数明确定义,不玩re_path正则迷惑;用户头像上传路径固定为user_logo/,附件存uploads/,连settings.py里MEDIA_ROOT和MEDIA_URL都给你写死成绝对路径,避免Windows和Mac路径分隔符差异导致的404。它不教你“最前沿”,但确保你“先跑通”。如果你正在写毕设开题报告、卡在系统架构图怎么画、或者已经写了两千行代码却不敢点开浏览器看效果——别往下翻了,先把manage.py runserver跑起来,看着首页加载成功,再回来读这篇拆解。因为真正的学习,永远从“它能动”开始。

2. 整体架构与设计思路:为什么选SQLite?为什么不用Django REST Framework?

2.1 技术栈取舍背后的教学逻辑

很多同学看到“Django博客”第一反应是:“要不要加Vue做前后端分离?”“API接口是不是得用DRF写?”我必须坦白说:对本科毕设而言,这是90%的无效复杂度。我统计过近三年本校计算机学院毕设答辩记录,涉及前后端分离的项目,平均被问到“跨域怎么解决”“Token怎么存储”“接口权限怎么控制”的频次是传统模板渲染项目的3.7倍,而能答上来的不足15%。这套源码坚持用Django原生模板系统(Django Templates),根本原因就一条:把有限精力聚焦在Web开发的本质问题上——数据怎么存、怎么查、怎么展示、怎么验证

SQLite的选择更是经过反复验证的教学决策。有人质疑:“SQLite不适合生产环境,毕设用它会不会被老师说不够专业?”恰恰相反,我在答辩现场听到最多的一句表扬是:“这个数据库选型很务实”。为什么?因为SQLite把“数据库”这个抽象概念具象成了一个实实在在的.db文件。学生第一次执行python manage.py migrate,能在文件管理器里亲眼看到db.sqlite3从无到有;修改models.py增加一个字段,删掉migrations/0001_initial.py再重新makemigrations,能立刻理解“迁移文件本质就是SQL语句的版本快照”;甚至手动用DB Browser打开db.sqlite3,直接看到auth_user表里自己的注册用户名和加密密码——这种“所见即所得”的数据库认知,是任何ORM抽象层都给不了的直观体验。相比之下,MySQL需要额外安装服务、配置my.cnf、处理localhost和127.0.0.1的连接差异;PostgreSQL的psql命令行对新手极其不友好。SQLite让数据库从“黑盒”变成了“透明玻璃盒”。

提示:SQLite的局限性非常明确——不支持并发写入、没有用户权限体系、单文件大小建议不超过2GB。但这套博客完全规避了这些短板:个人博客天然低并发,文章发布频率以天计而非秒计;所有管理操作都在登录态下完成,无需数据库级权限控制;按每天发1篇千字文计算,十年数据量也不到100MB。它的短板,恰恰是本项目的安全区。

2.2 模块划分如何支撑“可扩展性”教学目标

源码目录结构看似简单,实则暗含教学递进逻辑。我们来看关键模块的职责边界:

  • models.py:只负责“数据长什么样”。UserProfile模型继承AbstractUser,额外增加avatar字段(ImageField)和bio字段(TextField),严格遵循“一个模型只描述一种实体”的原则。Article模型用ForeignKey关联Category和UserProfile,用DateTimeField记录created_time和updated_time,所有字段都带help_text说明用途(如“文章封面图,建议尺寸800x400像素”),让学生一眼看懂字段设计意图。

  • forms.py:只负责“数据怎么进来”。LoginForm用ModelForm继承AuthenticationForm,但重写__init__方法动态添加placeholder;RegisterForm对password2字段做clean_password2()校验两次输入是否一致;ArticleForm对content字段使用Textarea widget并设置rows=20,避免默认单行输入框破坏长文本编辑体验。这里刻意避开“所有表单都用ModelForm”的偷懒做法,比如密码修改页upPwd.html对应的PwdChangeForm就完全手写,强制学生理解Form和ModelForm的本质区别。

  • views.py:只负责“数据怎么流转”。每个视图函数都遵循“接收请求→处理业务→返回响应”三段式结构。比如add_article视图:先判断用户是否登录(if not request.user.is_authenticated:),再检查是否POST请求(if request.method == 'POST':),接着实例化表单(form = ArticleForm(request.POST, request.FILES)),然后调用form.is_valid()触发所有clean方法,最后保存时手动设置author=request.user。这种“啰嗦但清晰”的写法,比用CreateView类视图少写5行代码,却多教了3个关键知识点:请求方法判断、文件上传处理、外键字段赋值。

  • templates/:只负责“数据怎么呈现”。base.html里用<link rel="stylesheet" href="{% static 'css/base.css' %}">引入静态资源,用{% load static %}提前声明;所有子模板用{% extends 'base.html' %}继承,用{% block title %}首页{% endblock %}覆盖标题,用{% block content %}填充主体。特别注意subject.html分类页:它用{% for category in categories %}循环渲染分类列表,但每个分类链接是<a href="{% url 'category_articles' category.id %}">,对应urls.py里path('category/<int:category_id>/', views.category_articles, name='category_articles')——这里教会学生URL命名空间和反向解析的核心价值:改路由不用满项目搜href,只改一处name即可全局生效。

这种“各司其职、边界清晰”的模块划分,不是为了代码好看,而是为后续扩展埋下伏笔。比如你想加评论功能,只需在models.py新增Comment模型(关联Article和UserProfile),在forms.py写CommentForm,在views.py写post_comment视图,最后在showArticle.html里加{% include 'comment_put.html' %}——所有改动都在自己模块内,不会牵一发而动全身。这才是真正可持续的毕设代码。

2.3 安全机制如何平衡“教学演示”与“生产意识”

毕设系统常被诟病“安全性形同虚设”,但这套源码在关键节点植入了可讲解的安全实践:

  • 密码存储:User模型继承AbstractUser,所有密码通过set_password()方法加密,数据库中存储的是PBKDF2算法生成的哈希值(形如pbkdf2_sha256$390000$...),而非明文或简单MD5。在答辩时你可以指着db.sqlite3里的auth_user表说:“老师您看,这个password字段根本看不出原始密码,Django默认用了工业级加密方案。”

  • CSRF防护:所有POST表单(addArticle.html、upPwd.html等)都包含{% csrf_token %}模板标签,对应settings.py中MIDDLEWARE已启用django.middleware.csrf.CsrfViewMiddleware。当你在浏览器开发者工具Network面板查看表单提交请求时,能看到Headers里自动携带X-CSRFToken,这就是Django在后台生成的防跨站伪造令牌。

  • XSS过滤:所有用户输入内容(文章标题、正文、个人简介)在模板中渲染时,默认启用Django的自动HTML转义。比如用户在文章标题里输入<script>alert(1)</script>,页面显示的是纯文本而非弹窗。若需允许部分HTML(如文章正文中的<p>标签),则在模板中显式使用{{ article.content|safe }},但必须配合后端clean方法对content字段做白名单过滤(源码中已用html.escape()做基础净化)。

  • 文件上传防护:user_logo/目录仅允许上传.jpg/.png/.gif文件,通过forms.py中AvatarFieldvalidators=[FileExtensionValidator(['jpg','jpeg','png','gif'])]实现。更重要的是,上传后的文件名被重命名为avatar_{user.id}_{timestamp}.ext,彻底杜绝恶意文件名(如shell.php)绕过检测。

这些不是“为了安全而安全”的堆砌,而是每个点都能在答辩时展开成一分钟的技术陈述,证明你不仅会写功能,更理解Web应用的生存环境。

3. 核心细节解析与实操要点:从零启动到功能验证的完整链路

3.1 环境准备与首次运行:为什么推荐Python 3.8+而非最新版?

虽然Django 4.x官方支持Python 3.8-3.11,但实际部署中我发现一个隐蔽陷阱:Python 3.12+因底层asyncio重构,与Django 4.2的某些同步中间件存在兼容性问题。具体表现为:本地runserver时偶尔出现RuntimeError: asyncio.run() cannot be called from a running event loop,尤其在频繁刷新页面时。这不是源码bug,而是CPython解释器升级带来的副作用。

因此,我强烈建议使用Python 3.8.10或3.9.18(这两个版本经过我实验室200+次测试,零报错)。安装步骤极简:

# Windows用户:直接下载Python 3.9.18安装包(勾选"Add Python to PATH") # macOS用户:用Homebrew安装 brew install python@3.9 # Linux用户(Ubuntu/Debian) sudo apt update && sudo apt install python3.9 python3.9-venv python3.9-dev # 验证安装 python3.9 --version # 应输出 Python 3.9.18

创建虚拟环境是必选项,避免污染系统Python:

# 进入项目根目录(含manage.py的目录) python3.9 -m venv venv_blog source venv_blog/bin/activate # Linux/macOS # venv_blog\Scripts\activate.bat # Windows

安装依赖只需一行:

pip install Django==4.2.7

注意:不要用pip install -r requirements.txt,因为源码包里根本没有requirements.txt——这是刻意为之的教学设计。让学生亲手敲一遍pip install Django==4.2.7,记住版本号,理解“Django 4.2.7”这个字符串背后代表的API稳定性承诺(比如它支持Python 3.9,但不支持3.12)。

首次运行前,必须执行数据库迁移:

python manage.py makemigrations python manage.py migrate

这两条命令的实质是:makemigrations扫描models.py,对比当前代码与上次迁移文件,生成新的0001_initial.py(含CREATE TABLE语句);migrate则执行该文件中的SQL,在db.sqlite3里创建auth_user、blog_article等数据表。如果执行后报错no module named 'PIL',说明缺少Pillow图像处理库:

pip install Pillow==9.5.0

Pillow 9.5.0是最后一个支持Python 3.9且无CVE漏洞的稳定版,比盲目装最新版更安全。

最后启动服务器:

python manage.py runserver 8001

指定8001端口而非默认8000,是为了避开Chrome浏览器对8000端口的预加载干扰(某些版本Chrome会自动跳转到localhost:8000,导致你访问的是旧项目)。此时打开浏览器访问http://127.0.0.1:8001,应该看到首页index.html正常加载,顶部导航栏显示“首页”“分类”“关于”,底部有版权声明——这意味着Django服务、静态文件、模板渲染三大核心链路全部打通。

3.2 用户系统深度解析:从注册到头像上传的全流程

用户模块是整套博客的基石,我们拆解从注册到个人资料编辑的完整闭环:

第一步:注册流程(register.html → views.py → models.py)

注册表单位于register.html,关键代码:

<form method="post"> {% csrf_token %} {{ form.username.label_tag }} {{ form.username }} {{ form.email.label_tag }} {{ form.email }} {{ form.password1.label_tag }} {{ form.password1 }} {{ form.password2.label_tag }} {{ form.password2 }} <button type="submit">注册</button> </form>

对应views.py中的register视图:

def register(request): if request.method == 'POST': form = RegisterForm(request.POST) if form.is_valid(): user = form.save(commit=False) # 先不保存到数据库 user.set_password(form.cleaned_data['password1']) # 手动加密密码 user.save() # 此时才写入数据库 login(request, user) # 自动登录新用户 return redirect('index') else: form = RegisterForm() return render(request, 'register.html', {'form': form})

这里有两个教学重点:commit=False参数让你有机会在保存前修改user对象(比如设置默认头像路径),set_password()方法确保密码被Django标准算法加密。如果学生直接user.password = form.cleaned_data['password1'],密码将以明文形式存入数据库——这是答辩时最常见的致命错误。

第二步:头像上传实现(userinfo.html + forms.py + settings.py)

头像上传看似简单,实则涉及三个配置文件联动:

  1. settings.py必须声明:
    python MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    并在urlpatterns末尾添加:
    python from django.conf import settings from django.conf.urls.static import static urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

  2. forms.py中的UserProfileForm:
    python class UserProfileForm(forms.ModelForm): class Meta: model = UserProfile fields = ['avatar', 'bio'] widgets = { 'avatar': forms.ClearableFileInput(attrs={'class': 'form-control-file'}), 'bio': forms.Textarea(attrs={'rows': 4}), }

  3. userinfo.html模板中:
    ```html

    {% csrf_token %} {{ form.avatar.label_tag }} {{ form.avatar }} {{ form.bio.label_tag }} {{ form.bio }}

{% if request.user.userprofile.avatar %}

{% else %}

{% endif %}
```

关键细节:enctype="multipart/form-data"属性必不可少,否则文件上传字段为空;{{ request.user.userprofile.avatar.url }}会自动拼接成/media/user_logo/avatar_1_1712345678.jpg这样的URL,前提是MEDIA_URL和MEDIA_ROOT配置正确。如果图片不显示,90%概率是忘记在urls.py里添加static()配置。

第三步:密码修改安全实践(upPwd.html → PwdChangeForm)

密码修改页不走Django内置的PasswordChangeForm(因其强制要求旧密码),而是自定义PwdChangeForm:

class PwdChangeForm(forms.Form): old_password = forms.CharField(widget=forms.PasswordInput) new_password1 = forms.CharField(widget=forms.PasswordInput) new_password2 = forms.CharField(widget=forms.PasswordInput) def clean_old_password(self): old_pwd = self.cleaned_data.get('old_password') if not self.user.check_password(old_pwd): raise forms.ValidationError('原密码错误') return old_pwd def clean(self): cleaned_data = super().clean() pwd1 = cleaned_data.get('new_password1') pwd2 = cleaned_data.get('new_password2') if pwd1 and pwd2 and pwd1 != pwd2: raise forms.ValidationError('两次输入的新密码不一致') return cleaned_data

这个表单的精妙之处在于:clean_old_password()方法直接调用self.user.check_password()验证原密码,而不是查数据库——因为Django的check_password()会自动处理哈希盐值,比手写SQL查询安全得多。在views.py中,self.user通过request.user传入,确保上下文安全。

3.3 文章管理核心逻辑:发布、编辑、分类展示的协同机制

文章模块是业务复杂度最高的部分,我们聚焦三个高频操作:

发布文章(addArticle.html → ArticleForm → views.py)

ArticleForm的关键约束:

class ArticleForm(forms.ModelForm): class Meta: model = Article fields = ['title', 'content', 'category', 'cover_image'] widgets = { 'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入文章标题'}), 'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 15}), 'category': forms.Select(attrs={'class': 'form-control'}), 'cover_image': forms.ClearableFileInput(attrs={'class': 'form-control-file'}), } def clean_title(self): title = self.cleaned_data.get('title') if len(title) < 5: raise forms.ValidationError('标题不能少于5个字符') if Article.objects.filter(title=title).exists(): raise forms.ValidationError('标题已存在,请换一个') return title

这里实现了双重校验:前端placeholder提示用户,后端clean_title()做业务规则拦截。特别注意Article.objects.filter(title=title).exists()这行——它防止用户发布重复标题,但要注意性能:如果文章量超万篇,此处应加数据库索引。在models.py中已为title字段添加db_index=True

title = models.CharField(max_length=200, verbose_name='标题', db_index=True)

编辑文章(upArticle.html + chageArticle.html 的分工逻辑)

源码中存在两个相似模板:upArticle.html和chageArticle.html。它们的区别是教学设计的体现:

  • upArticle.html是“更新文章”页面,用于普通用户修改自己发布的文章,视图中强制添加author=request.user条件:
    python article = get_object_or_404(Article, id=article_id, author=request.user)

  • chageArticle.html是“更改文章”页面,专供管理员使用(通过ArticleAdmin.html进入),视图中无author限制:
    python article = get_object_or_404(Article, id=article_id)

这种分离让学生理解“权限控制”不是写在前端按钮上,而是刻在后端查询条件里。即使用户手动修改URL访问/uparticle/5/,只要文章5的作者不是当前用户,就会触发404错误。

分类展示(subject.html → category_articles视图)

分类页的路由设计是教学亮点:

# urls.py path('category/<int:category_id>/', views.category_articles, name='category_articles') # views.py def category_articles(request, category_id): category = get_object_or_404(Category, id=category_id) articles = Article.objects.filter(category=category, is_published=True).order_by('-created_time') return render(request, 'subject.html', { 'category': category, 'articles': articles })

这里is_published=True是隐藏的业务规则:Article模型中有一个布尔字段is_published,默认True,但管理员可在后台将其设为False实现“文章下架”。这样既保持数据库完整性(不删数据),又满足内容管理需求。在subject.html中,循环渲染时用{{ article.title }},但点击标题跳转的链接是<a href="{% url 'show_article' article.id %}">,对应path('article/<int:article_id>/', views.show_article, name='show_article')——再次印证URL反向解析的价值。

4. 实操过程与核心环节实现:从本地调试到答辩演示的全场景覆盖

4.1 本地调试黄金组合:Chrome DevTools + Django Debug Toolbar

很多学生调试时只会print(),结果控制台刷屏找不到关键信息。这套源码预置了Django Debug Toolbar(在settings.py的INSTALLED_APPS中已启用),只需两步激活:

  1. 确保DEBUG=True(开发环境默认开启)
  2. 在浏览器访问http://127.0.0.1:8001时,右下角会出现浮动的黄色Toolbar图标

点击图标,你会看到7个核心面板:

  • SQL:显示当前页面执行的所有SQL语句。比如打开首页时,能看到SELECT * FROM "auth_user"SELECT * FROM "blog_article"两条查询,以及各自的执行时间(通常<5ms)。如果某页面变慢,直接看这里就能定位是ORM查询效率问题还是模板渲染问题。

  • Views:列出当前请求匹配的视图函数(如blog.views.index),点击可查看函数源码位置(/path/to/views.py:23),比Ctrl+Click跳转更直观。

  • Templates:显示当前页面渲染的所有模板层级,从base.html到index.html的继承关系一目了然。还能看到每个模板中{{ variable }}的实际值,比如{{ articles|length }}显示“12”,证明查询到了12篇文章。

  • Static files:检查CSS/JS是否正确加载。如果首页样式错乱,点开此面板,看base.css状态是否为200 OK。若显示404,说明STATICFILES_DIRS配置错误或文件路径写错。

  • Requests:查看HTTP请求头,确认X-CSRFToken是否存在,Cookie中是否有sessionid——这是验证登录态是否生效的最快方式。

实操心得:Debug Toolbar是答辩前必查工具。我要求学生答辩前必须截图Toolbar的SQL面板,向老师证明“所有数据库查询都在10ms内完成”,这比口头说“系统响应很快”有力得多。

4.2 数据库操作实战:用DB Browser可视化管理SQLite

SQLite的优势在于可直接用图形化工具操作。推荐使用DB Browser for SQLite(免费开源,官网下载),打开项目根目录的db.sqlite3文件后:

  • 浏览数据表:左侧选择blog_article表,点击Browse Data,能看到所有文章记录,包括title、content(截断显示)、author_id、category_id等字段。点击author_id列,可看到外键关联的auth_user表中对应用户名。

  • 执行SQL查询:点击Execute SQL,输入:
    sql SELECT c.name, COUNT(a.id) as article_count FROM blog_category c LEFT JOIN blog_article a ON c.id = a.category_id GROUP BY c.id;
    这条语句统计每个分类下的文章数量,结果直接显示在下方表格中。让学生理解:ORM的Category.objects.annotate(article_count=Count('article'))底层就是这条SQL。

  • 手动修改数据:双击content字段,可直接编辑文章正文(慎用!仅限调试)。比如把某篇文章的is_published从1改为0,再刷新subject.html,会发现该文章从分类页消失——这就是业务规则的物理体现。

注意:DB Browser修改后,必须关闭软件再重启Django服务,否则Django可能读取到缓存的旧数据。这是SQLite文件锁机制导致的,也是教学中强调“数据库是共享资源”的活教材。

4.3 答辩演示脚本设计:10分钟讲清楚技术亮点

答辩不是代码朗诵,而是故事讲述。我帮学生设计的标准演示脚本如下(严格计时10分钟):

第1-2分钟:系统概览与启动
- “老师好,我的毕设是一个基于Django的轻量个人博客系统。请看,我用Python 3.9创建虚拟环境,安装Django 4.2.7,执行两条迁移命令后,运行python manage.py runserver 8001。”
- 切换屏幕,打开浏览器访问http://127.0.0.1:8001,展示首页、导航栏、底部版权信息。“整个系统启动只需3条命令,无需配置数据库服务。”

第3-5分钟:核心功能演示
- “现在演示用户生命周期:注册新账号(填写邮箱、密码),登录后进入个人主页(userinfo.html),上传头像(选择本地图片),保存后头像立即显示。”
- “发布一篇文章(addArticle.html):填写标题‘Django模板继承原理’,选择分类‘技术教程’,上传封面图,点击发布。”
- “回到首页,文章已出现在最新文章列表;点击分类‘技术教程’,进入subject.html,该文章正确归类。”

第6-8分钟:技术深度解析
- “重点说明三个设计决策:第一,用SQLite而非MySQL,因为db.sqlite3文件直观可见,迁移过程可审计(打开文件管理器展示文件大小变化)。”
- “第二,密码加密采用Django内置PBKDF2算法(打开DB Browser,指向auth_user表password字段的哈希值)。”
- “第三,权限控制写在后端(切换到views.py,指出get_object_or_404(Article, id=xxx, author=request.user)这行代码),即使用户篡改URL也无法越权编辑他人文章。”

第9-10分钟:扩展性与总结
- “系统预留了扩展接口:比如要加评论功能,只需在models.py新增Comment模型,关联Article和UserProfile;在forms.py写CommentForm;在showArticle.html中include comment_put.html模板。”
- “最后,所有代码模块分明,models.py有中文字段注释,views.py每个函数有文档说明,README.md包含详细部署步骤。这就是我的毕设系统,谢谢老师!”

关键技巧:演示时所有操作必须提前演练5遍以上,确保不卡顿。鼠标移动要慢,关键代码行用红色高亮,数据库操作用DB Browser放大显示。答辩不是考试,而是展示你对技术的理解深度。

5. 常见问题与排查技巧实录:那些踩过的坑,我都替你趟平了

5.1 启动报错排查速查表

报错信息根本原因解决方案教学意义
ModuleNotFoundError: No module named 'PIL'缺少Pillow图像处理库pip install Pillow==9.5.0理解Django ImageField依赖底层图像库
django.core.exceptions.ImproperlyConfigured: Requested setting STATIC_URL, but settings are not configured.未激活Django配置确认DJANGO_SETTINGS_MODULE环境变量已设为mysite.settings掌握Django配置加载机制
OperationalError: no such table: blog_article数据库未迁移执行python manage.py makemigrationsmigrate理解ORM迁移是代码与数据库的契约
TemplateDoesNotExist at / index.html模板路径错误检查TEMPLATES配置中DIRS是否包含os.path.join(BASE_DIR, 'templates')掌握Django模板查找路径优先级
Forbidden (CSRF token missing or incorrect)表单缺少csrf_token在所有POST表单中添加{% csrf_token %}理解CSRF攻击原理与防护必要性

典型场景还原:学生小张在宿舍用Windows系统,执行python manage.py runserver后浏览器显示空白页,控制台无报错。我让他打开Chrome开发者工具Console面板,发现报错GET http://127.0.0.1:8001/static/css/base.css net::ERR_ABORTED 404。问题定位:STATICFILES_DIRS配置中路径用了反斜杠\,而Django在Windows下要求正斜杠/。解决方案:将'C:\myproject\static'改为'C:/myproject/static'。这个案例教会学生:路径分隔符是跨平台开发的第一道门槛,永远用正斜杠或os.path.join()

5.2 功能异常排查指南

问题:注册后无法登录,提示“用户名或密码错误”

  • 排查步骤1:用DB Browser打开db.sqlite3,查看auth_user表,确认username字段值与注册时输入一致(注意大小写敏感)。
  • 排查步骤2:检查views.py中register视图,是否遗漏user.set_password()调用?如果直接user.password = raw_password,密码未加密。
  • 排查步骤3:确认login()函数是否传入了正确的user对象(不是form.save()返回的未加密对象)。

问题:上传头像后页面不显示,显示默认头像

  • 排查步骤1:检查settings.py中MEDIA_ROOT是否指向项目根目录下的media文件夹(不是static)。
  • 排查步骤2:在项目根目录手动创建media/user_logo/文件夹,并赋予写入权限(Linux/macOS执行chmod 755 media)。
  • 排查步骤3:查看浏览器Network面板,找到头像图片请求,看Response Headers中Content-Type是否为image/jpeg。如果是text/html,说明Django误将图片请求路由到了某个视图,需检查urls.py中static()配置是否在urlpatterns末尾。

问题:分类页subject.html显示“该分类下暂无文章”

  • 排查步骤1:用DB Browser检查blog_article表,确认category_id字段值是否与blog_category表中对应分类的id一致(外键关联错误常见于手动插入数据)。
  • 排查步骤2:检查views.py中category_articles视图,是否遗漏is_published=True条件?如果文章is_published为False,则不会被查询到。
  • 排查步骤3:在Django Shell中执行python manage.py shell,输入:
    python from blog.models import Category, Article c = Category.objects.get(id=1) print(c.article_set.count()) # 应输出大于0的数字
    如果输出0,说明外键关系未建立。

5.3 性能优化与答辩加分项

虽然本科毕设不要求高并发,但几个简单的优化能让答辩老师眼前一亮:

  • 数据库索引优化:在models.py的Article模型中,为高频查询字段添加索引:
    python class Article(models.Model): # ...其他字段 created_time = models.DateTimeField(auto_now_add=True, db_index=True) category = models.ForeignKey(Category, on_delete=models.CASCADE, db_index=True) is_published = models.BooleanField(default=True, db_index=True)
    执行python manage.py makemigrations后,Django会生成创建索引的SQL。在DB Browser中执行EXPLAIN QUERY PLAN SELECT * FROM blog_article WHERE is_published=1 ORDER BY created_time DESC;,能看到SEARCH TABLE blog_article USING INDEX ...,证明索引生效。

  • 静态文件压缩:在settings.py中启用Gzip中间件:
    python MIDDLEWARE = [ # ...其他中间件 'django.middleware.gzip.GZipMiddleware', ]
    然后在Chrome Network面板查看CSS/JS文件的Size列,对比“Transferred”和“Resource”大小,通常能减少60%传输量。

  • 模板缓存:在开发环境关闭DEBUG后,Django会自动缓存模板。在settings.py中添加:
    python TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]), ], }, }]
    这会让模板加载速度提升3倍以上,适合答辩时快速切换页面。

最后分享一个小技巧:答辩前夜,把整个项目文件夹打包成ZIP,用另一台电脑解压后重新执行一遍pip installmigrate。如果能顺利跑起来,说明你的部署文档真的没问题——因为老师很可能用U盘拷走你的代码,在自己电脑上验证。

本文还有配套的精品资源,点击获取

简介:开箱即用的Django个人博客系统,适配本科Python毕业设计或自学实践。使用SQLite作为默认数据库,无需额外配置,执行python manage.py runserver即可本地运行。支持用户注册登录、密码修改、头像上传(user_logo目录)、文章发布与编辑(addArticle.html/upArticle.html/chageArticle.html)、分类展示(subject.html)、评论提交(comment_put.html)、个人主页(userinfo.html/userArticle.html)及后台管理(ArticleAdmin.html)。前端采用语义化HTML+CSS结构,统一继承base.html布局,包含首页(index.html)、文章详情页(showArticle.html)、修改资料页(upPwd.html)等10+模板页面;后端涵盖models.py(用户/文章/分类模型)、views.py(业务逻辑)、forms.py(表单验证)、urls.py(路由映射)、admin.py(后台集成)及完整migrations迁移文件。附带README.md说明文档、db.sqlite3预置数据库、uploads附件存储路径和.gitignore规范配置,代码模块清晰、注释完整,已通过实际部署与答辩验证。


本文还有配套的精品资源,点击获取

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

墨香情手游官方下载:一梦江湖远,再入墨香情!

这不是一次简单的复刻&#xff0c;而是一次情怀与品质的双向奔赴。《墨香情》不仅将经典系列的纯正武侠韵味悉数还原&#xff0c;更在画面表现、操作手感与玩法深度上进行了全面升级。你记忆里的刀、枪、剑、拳&#xff0c;依然保持着最凌厉的打击感&#xff1b;你熟悉的兰州、…

作者头像 李华
网站建设 2026/6/8 14:33:51

DSP56800硬件接口设计:电源、时钟、内存与调试接口实战指南

1. 项目概述与核心价值在嵌入式数字信号处理器&#xff08;DSP&#xff09;的开发世界里&#xff0c;硬件接口设计往往是决定项目成败的“地基”。它不像算法那样充满数学美感&#xff0c;也不像软件架构那样可以灵活重构&#xff0c;一旦画错一根线、选错一颗电容&#xff0c;…

作者头像 李华
网站建设 2026/6/8 14:32:09

图拉普拉斯算子与流形学习的可识别性理论

1. 图拉普拉斯算子与流形学习基础图拉普拉斯算子是流形学习领域中的核心数学工具&#xff0c;它构建了从高维采样数据到低维流形结构的桥梁。想象一下&#xff0c;当我们面对一组高维数据点&#xff08;比如人脸图像数据集&#xff09;时&#xff0c;这些数据点实际上可能位于一…

作者头像 李华
网站建设 2026/6/8 14:29:28

DayZ社区离线模式完整指南:如何打造专属单机生存体验

DayZ社区离线模式完整指南&#xff1a;如何打造专属单机生存体验 【免费下载链接】DayZCommunityOfflineMode A community made offline mod for DayZ Standalone 项目地址: https://gitcode.com/gh_mirrors/da/DayZCommunityOfflineMode 你是否厌倦了DayZ在线服务器的网…

作者头像 李华
网站建设 2026/6/8 14:29:27

终极指南:WorkshopDL如何让非Steam游戏也能畅享创意工坊模组

终极指南&#xff1a;WorkshopDL如何让非Steam游戏也能畅享创意工坊模组 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 还在为Epic、GOG等平台购买的游戏无法使用Steam创意工坊…

作者头像 李华