目录
感谢
感谢锋哥的指导。由于我使用的是MySQL 5.7版本,因此对项目代码进行了相应的调整。详细修改过程及源代码,请参考锋哥在B站发布的视频教程:
基于Django框架的博客系统的开发与实现https://www.bilibili.com/video/BV1GJ6uYpEwK
在此,也向锋哥表示诚挚的谢意!
摘要
本项目利用Django框架,结合现代Web开发的最佳实践,构建了一个功能全面、易于扩展的博客平台。通过此项目,开发者可以学习到如何使用Django进行模型设计、视图逻辑编写、模板渲染以及静态文件管理等核心技能,同时掌握了用户认证、文章管理等博客系统必备功能的实现方法。
项目代码地址:
上一篇:
主页实现
通用模板实现
在技术架构层面,博客网站的全局导航栏、侧边功能栏、页脚信息等公共组件存在高度复用特性。基于Django模板继承机制,我们采用组件化开发策略:建立基模板(base.html)预置公共HTML结构,通过{% block content %}定义可扩展区域。各子模板通过{% extends 'base.html' %}语法继承基模板,仅在特定区块重写个性化内容。这种实现方式符合DRY原则,既保障了页面风格统一性,又使模板维护效率提升,同时为后续功能扩展预留标准接口。
templates目录下新建通用模版文件base.html,这里的block标签用于定义一个可供子模板覆盖的区域
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<meta charset="UTF-8">
<title>{% block title %}博客首页{% endblock %}-Powered by python222</title>
<link href="{% static "bootstrap-5.3.3/css/bootstrap.css" %}" rel="stylesheet"/>
<link href="{% static "css/blog.css" %}" rel="stylesheet"/>
<script src="{% static "bootstrap-5.3.3/js/bootstrap.js" %}"></script>
<script src="{% static "js/jquery-1.11.2.min.js" %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4">
<img style="width: 326px;height: 60px" alt="开源博客系统" src="{% static "images/logo.png" %}">
</div>
<div class="col-md-8">
<iframe style="float: right;" width="400" scrolling="no" height="60" frameborder="0"
allowtransparency="true" src="http://i.tianqi.com/index.php?c=code&id=12&icon=1&num=5&py=zhanggongqu"></iframe>
</div>
</div>
<div class="row">
<div class="col-md-12" style="padding-top: 10px;padding-bottom: 10px">
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'article' id 1 0 %}">博客首页</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/album/1/1.html">我的相册</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/user/about/1.html">关于我</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/message/1/1.html">留言</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/">博客后台管理</a>
</li>
</ul>
<form class="d-flex" role="search" method="post" action="/search/1"
onsubmit="return checkSearchForm()">
{% csrf_token %}
<input class="form-control me-2" type="search" placeholder="请输入搜索内容..."
aria-label="Search" name="v" id="v" value="{{ v }}">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
</div>
</div>
<div class="row">
<div class="col-md-9">
{% block content %}{% endblock %}
</div>
<div class="col-md-3">
<div class="data_list">
<div class="data_list_title">
<img src="/static/images/user_icon.png">
关于我
</div>
<div class="user_image">
<img src="/media/avatar/222.jpg">
</div>
<div class="nickName">小龙ssss</div>
<div class="userSign">(3年python新手,小程序员)</div>
</div>
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/byType_icon.png' %}"/>
按日志类别
</div>
<div class="datas">
<ul>
<li><span><a href="/1/1/1.html">Python基础</a></span></li>
<li><span><a href="/1/1/2.html">数据分析</a></span></li>
<li><span><a href="/1/1/3.html">人工智能</a></span></li>
</ul>
</div>
</div>
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/link_icon.png' %}"/>
友情链接
</div>
<div class="datas">
<ul>
<li><span><a href="http://www.java1234.com/" target="_blank">java知识分享网</a></span></li>
<li><span><a href="http://blog.java1234.com/index.html" target="_blank">java开源博客</a></span>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div align="center" style="padding-top: 120px">
<span style="float: left;">Powered by <a href="http://python222.com"
target="_blank">小龙ssss</a></span>
Copyright © 2023-2025 小龙ssss 版权所有
</div>
</div>
</div>
</div>
{% block script %}{% endblock %}
<script>
function checkSearchForm() {
var v = $("#v").val();
if (v == null || v == '') {
alert("请输入搜索内容!");
return false;
}
return true;
}
</script>
</body>
</html>
templates下再新建一个article.html博客页面,通过extends继承base.html。
通过block标签重写父模板:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/list_icon.png' %}"/>
博客列表
</div>
<div class="datas">
博客列表内容
</div>
</div>
{% endblock %}
article / views.py 定义article函数,来实现查询帖子信息,转发帖子页面:
def article(request, id, page, typeId):
"""
查询帖子信息
:param request:
:return:
"""
print(id, page, typeId)
return render(request, 'article.html', locals())
article / urls.py下再增加映射:
# 文章列表
path('<int:id>/<int:page>/<int:typeId>.html', article, name="article"),
用户登录成功后的逻辑,我们改成 重定向到帖子页面:
user/urls.py:
# from django.shortcuts import redirect
# from django.urls import reverse
kwargs = {'id': request.user.id, 'page': 1, 'typeId': 0}
return redirect(reverse('article', kwargs=kwargs))
我们启动测试下,登录后,跳转到帖子主页:
Bug出现
这里可能会出现一个Bug,即:
GET /media/avatar/222.jpg HTTP/1.1" 404
也就是media底下的图片加载不出来。
在主urls.py文件中加入如下代码,确保Django能够正确处理媒体文件请求。注意这段代码应该只在DEBUG=True
(settings.py中设置)时生效。
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
如果还不行,在settings.py中,数组TEMPLATES的context_processors中添加一行代码:
# 添加以下这行
'django.template.context_processors.media',
应该就能解决这个问题,如果还有bug,我也无能为力。
右侧关于博主信息动态显示实现
要求不同的用户显示不一样,有头像的用户用头像,没有头像的用户用默认的图片。
我们后端从数据库获取数据,然后动态显示到页面上。
(数据库里,我们先直接加上数据
avatar:avatar/xlsss.png,
name:小龙ssss,
introduce:3年python新手,小程序员)
用户登录后,会把用户信息直接存会话中,所以页面可以直接获取。在base.html中修改:
<div class="data_list">
<div class="data_list_title">
<img src="/static/images/user_icon.png">
关于我
</div>
<div class="user_image">
{% if user.avatar %}
<img src="{{ user.avatar.url }}"/>
{% else %}
<img src="{% static 'images/user.jpg' %}"/>
{% endif %}
</div>
<div class="nickName">{{ user.name }}</div>
<div class="userSign">({{ user.introduce }})</div>
</div>
右侧日志类别动态显示实现
根据多用户博客系统的业务需求,每个日志分类需明确归属特定用户。为此我们在分类模型设计中添加用户外键字段(user),通过外键关联实现用户与分类的所属关系绑定,确保数据维度的用户隔离性。。
article/models.py
# from user.models import MyUser
user = models.ForeignKey(MyUser, on_delete=models.CASCADE, verbose_name='用户')
再通过makemigrations和migrate,生成数据库表:
makemigrations article
# 然后选1
外键连接主键,这里我们的id是主键,值为1,主键是什么就输入什么
migrate article
因为好几个页面都要用到这个类别显示数据,所以我们把这些数据放到context全局上下文中,来实现 复用,也方便维护。
article下新建mycontext.py
from article.models import ArticleType
def getAllArticleType(request):
"""
获取所有帖子类别
:param request:
:return:
"""
return {"articleTypeList": ArticleType.objects.all()}
settings.py里配置下全局上下文,
TEMPLATES里添加,
# 此处添加新的全局上下文
'article.mycontext.getAllArticleType',
修改base.html:
<div class="datas">
<ul>
{% for type in articleTypeList %}
<li><span><a href="{% url 'article' id 1 type.id %}">{{ type.name }}</a>
</span></li>
{% endfor %}
</ul>
</div>
运行:
右侧友情链接动态显示实现
link / models.py 里新建友情链接类:
from django.db import models
from user.models import MyUser
class LinkInfo(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField('链接名称', max_length=50)
url = models.CharField('链接地址', max_length=200)
remark = models.CharField('备注', max_length=500, blank=True)
user = models.ForeignKey(MyUser, on_delete=models.CASCADE, verbose_name='用户')
def __str__(self):
return str(self.name)
class Meta:
verbose_name = '友情链接管理'
verbose_name_plural = '友情链接管理'
再通过makemigrations,migrate,生成数据库表,
makemigrations link
migrate
新建查询,添加以下数据:
INSERT INTO `link_linkinfo` (`id`, `name`, `url`, `remark`, `user_id`)
VALUES('1','java知识分享网','http://www.java1234.com/','好网站','1');
INSERT INTO `link_linkinfo` (`id`, `name`, `url`, `remark`, `user_id`)
VALUES('2','java开源博客','http://blog.java1234.com/index.html','好博客','1');
link模块下新建mycontext.py
from link.models import LinkInfo
def getAllLink(request):
"""
获取所有友情链接
:param request:
:return:
"""
return {"linkList": LinkInfo.objects.all()}
settings.py里配置下全局上下文, TEMPLATES里添加,
'link.mycontext.getAllLink'
base.html修改:
<ul>
{% for link in linkList %}
<li><span><a href="{{ link.url }}" target="_blank">{{ link.name }}</a></span>
</li>
{% endfor %}
</ul>
后续
持续开发中。。。