基于Django框架的博客平台开发与实现(二)
感谢
感谢锋哥的指导。由于我使用的是MySQL 5.7版本,因此对项目代码进行了相应的调整。详细修改过程及源代码,请参考锋哥在B站发布的视频教程:
基于Django框架的博客系统的开发与实现https://www.bilibili.com/video/BV1GJ6uYpEwK在此,也向锋哥表示诚挚的谢意!
摘要
本项目利用Django框架,结合现代Web开发的最佳实践,构建了一个功能全面、易于扩展的博客平台。通过此项目,开发者可以学习到如何使用Django进行模型设计、视图逻辑编写、模板渲染以及静态文件管理等核心技能,同时掌握了用户认证、文章管理等博客系统必备功能的实现方法。
基于Django框架的博客平台开发与实现(一)https://blog.youkuaiyun.com/m0_50313048/article/details/145979217
前端架构搭建:
这边下载的版本是5.3.3
在settings.py中,配置静态资源和媒体资源:
STATIC_URL = '/static/' # 设置静态资源的URL
STATICFILES_DIRS = [BASE_DIR / 'publicStatic'] # 设置静态资源的保存路径
STATIC_ROOT = BASE_DIR / 'static' # 设置静态资源的打包路径
# 设置媒体资源的保存路径
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"
我们在项目目录下,新建static、publicStatic、media三个文件夹。然后从网站上下载bootstrap5开发包,放入publicStatic
我们来测试下前端:
templates文件夹下新建test.html
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<meta charset="UTF-8">
<title>Title</title>
<link href="{% static 'bootstrap-5.3.3/css/bootstrap.css' %}" rel="stylesheet"/>
<script src="{% static 'bootstrap-5.3.3/js/bootstrap.js' %}"></script>
</head>
<body>
<button class="btn btn-primary">测试按钮</button>
</body>
</html>
article的views.py的TestView类的get方法修改下:
return render(request, 'test.html')
启动项目,浏览器请求地址: http://127.0.0.1:8000/article/test
用户登录和注册实现
用户登录和注册静态网页模版实现
准备两个静态html页面,即登录静态模版页面login.html和注册静态模版页面register.html。
login.html:
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<title>博客系统用户登录界面</title>
<script src="{% static "js/jquery-1.11.2.min.js" %}"></script>
<link rel="stylesheet" href="{% static "css/login.css" %}" type="text/css">
<script type="text/javascript">
$(function () {
//得到焦点
$("#password").focus(function () {
$("#left_hand").animate({
left: "150",
top: " -38"
}, {
step: function () {
if (parseInt($("#left_hand").css("left")) > 140) {
$("#left_hand").attr("class", "left_hand");
}
}
}, 2000);
$("#right_hand").animate({
right: "-64",
top: "-38px"
}, {
step: function () {
if (parseInt($("#right_hand").css("right")) > -70) {
$("#right_hand").attr("class", "right_hand");
}
}
}, 2000);
});
//失去焦点
$("#password").blur(function () {
$("#left_hand").attr("class", "initial_left_hand");
$("#left_hand").attr("style", "left:100px;top:-12px;");
$("#right_hand").attr("class", "initial_right_hand");
$("#right_hand").attr("style", "right:-112px;top:-12px");
});
});
function checkForm() {
var username = $("#username").val();
var password = $("#password").val();
if (username == null || username == "") {
$("#error").html("用户名不能为空!");
return false;
}
if (password == null || password == "") {
$("#error").html("密码不能为空!");
return false;
}
return true;
}
</script>
</head>
<body>
<DIV class="top_div">
</DIV>
<form action="login" method="post" onsubmit="return checkForm()">
{% csrf_token %}
<DIV style="background: rgb(255, 255, 255); margin: -100px auto auto;
border: 1px solid rgb(231, 231, 231); border-image: none; width: 400px; height:
230px; text-align: center;">
<DIV style="width: 165px; height: 96px; position: absolute;">
<DIV class="tou">
</DIV>
<DIV class="initial_left_hand" id="left_hand">
</DIV>
<DIV class="initial_right_hand" id="right_hand">
</DIV>
</DIV>
<P style="padding: 30px 0px 10px; position: relative;">
<SPAN class="u_logo"></SPAN>
<INPUT id="username" name="username" class="ipt" type="text"
placeholder="请输入用户名"
value="{{ username }}">
</P>
<P style="position: relative;">
<SPAN class="p_logo"></SPAN>
<INPUT id="password" name="password" class="ipt" type="password" placeholder="请输入密码" value="{{ password }}">
</P>
<DIV style="height: 50px; line-height: 50px; margin-top: 30px; border-top-color: rgb(231, 231, 231); border-top-width: 1px; border-top-style: solid;">
<P style="margin: 0px 35px 20px 45px;">
<SPAN style="float: left;">小龙ssss博客系统 <a href="register.html"
style="color: darkcyan">>>用户注册</a></SPAN>
<SPAN style="float: right;">
<input type="submit"
style="background: rgb(0, 142, 173); padding: 7px 10px;
border-radius: 4px; border: 1px solid rgb(26, 117, 152); border-image: none;
color: rgb(255, 255, 255); font-weight: bold;"
value="登录"/>
</SPAN>
</P>
</DIV>
<span style="padding-top: 5px"><font color="red" id="error">{{ errorinfo}}</font></span>
</DIV>
</form>
<div style="text-align:center;padding-top: 30px">
Copyright © 2015-2025 <a href="https://blog.youkuaiyun.com/m0_50313048"
target="_blank">小龙ssss</a> 版权所有
</div>
</body>
</html>
register.html:
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<title>博客系统用户注册</title>
<script src="{% static "js/jquery-1.11.2.min.js" %}"></script>
<link rel="stylesheet" href="{% static "css/login.css" %}" type="text/css">
<script type="text/javascript">
$(function () {
//得到焦点
$("#password").focus(function () {
$("#left_hand").animate({
left: "150",
top: " -38"
}, {
step: function () {
if (parseInt($("#left_hand").css("left")) > 140) {
$("#left_hand").attr("class", "left_hand");
}
}
}, 2000);
$("#right_hand").animate({
right: "-64",
top: "-38px"
}, {
step: function () {
if (parseInt($("#right_hand").css("right")) > -70) {
$("#right_hand").attr("class", "right_hand");
}
}
}, 2000);
});
//失去焦点
$("#password").blur(function () {
$("#left_hand").attr("class", "initial_left_hand");
$("#left_hand").attr("style", "left:100px;top:-12px;");
$("#right_hand").attr("class", "initial_right_hand");
$("#right_hand").attr("style", "right:-112px;top:-12px");
});
//得到焦点
$("#password2").focus(function () {
$("#left_hand").animate({
left: "150",
top: " -38"
}, {
step: function () {
if (parseInt($("#left_hand").css("left")) > 140) {
$("#left_hand").attr("class", "left_hand");
}
}
}, 2000);
$("#right_hand").animate({
right: "-64",
top: "-38px"
}, {
step: function () {
if (parseInt($("#right_hand").css("right")) > -70) {
$("#right_hand").attr("class", "right_hand");
}
}
}, 2000);
});
//失去焦点
$("#password2").blur(function () {
$("#left_hand").attr("class", "initial_left_hand");
$("#left_hand").attr("style", "left:100px;top:-12px;");
$("#right_hand").attr("class", "initial_right_hand");
$("#right_hand").attr("style", "right:-112px;top:-12px");
});
});
function checkForm() {
var username = $("#username").val();
var password = $("#password").val();
var password2 = $("#password2").val();
if (username == null || username == "") {
$("#error").html("用户名不能为空!");
return false;
}
if (password == null || password == "") {
$("#error").html("密码不能为空!");
return false;
}
if (password2 == null || password2 == "") {
$("#error").html("确认密码不能为空!");
return false;
}
if (password != password2) {
$("#error").html("确认密码输入不正确!");
return false;
}
return true;
}
</script>
</head>
<body>
<DIV class="top_div">
</DIV>
<form action="register" method="post" onsubmit="return checkForm()">
{% csrf_token %}
<DIV style="background: rgb(255, 255, 255); margin: -100px auto auto; border: 1px solid rgb(231, 231, 231); border-image: none; width: 400px; height: 280px; text-align: center;">
<DIV style="width: 165px; height: 96px; position: absolute;">
<DIV class="tou">
</DIV>
<DIV class="initial_left_hand" id="left_hand">
</DIV>
<DIV class="initial_right_hand" id="right_hand">
</DIV>
</DIV>
<P style="padding: 30px 0px 10px; position: relative;">
<SPAN class="u_logo"></SPAN>
<INPUT id="username" name="username" class="ipt" type="text" placeholder="请输入用户名"
value="{{ username }}">
</P>
<P style="position: relative;">
<SPAN class="p_logo"></SPAN>
<INPUT id="password" name="password" class="ipt" type="password" placeholder="请输入密码"
value="{{ password }}">
</P>
<P style="padding-top:10px;position: relative;">
<SPAN class="p_logo" style="margin-top: 10px;"></SPAN>
<INPUT id="password2" name="password2" class="ipt" type="password" placeholder="请输入确认密码"
value="{{ password2 }}">
</P>
<DIV style="height: 50px; line-height: 50px; margin-top: 30px; border-top-color: rgb(231, 231, 231); border-top-width: 1px; border-top-style: solid;">
<P style="margin: 0px 35px 20px 45px;">
<SPAN style="float: left;">小龙ssss博客系统 <a href="login.html"
style="color: darkcyan">>>用户登录</a></SPAN>
<SPAN style="float: right;">
<input type="submit"
style="background: rgb(0, 142, 173); padding: 7px 10px; border-radius: 4px; border: 1px solid rgb(26, 117, 152); border-image: none; color: rgb(255, 255, 255); font-weight: bold;"
value="注册"/>
</SPAN>
</P>
</DIV>
<span style="padding-top: 5px"><font color="red" id="error">{{ info }}</font></span>
</DIV>
</form>
<div style="text-align:center;padding-top: 30px">
Copyright © 2015-2025 <a href="https://blog.youkuaiyun.com/m0_50313048" target="_blank">小龙ssss</a> 版权所有
</div>
</body>
</html>
把login.html和register.html模版文件放入templates下;另外再把开发包中的css,js,images静态文件放publicStatic下面;(此操作用windows资源管理器操作就行,最好别用pycharm,可能会卡)
user / views.py 添加跳转逻辑:
def toLoginPage(request):
"""
跳转登录页面
:param request:
:return:
"""
return render(request, 'login.html')
def toRegisterPage(request):
"""
跳转到注册页面
:param request:
:return:
"""
return render(request, 'register.html')
user / urls.py 添加 请求映射:
from django.urls import path
from article.views import TestView
from user.views import toLoginPage, toRegisterPage
urlpatterns = [
# 跳转登录页面
path('login.html', toLoginPage, name='toLoginPage'),
# 跳转注册页面
path('register.html', toRegisterPage, name='toRegisterPage'),
]
根路径请求,我们选择直接跳转到登录页面:
# article / urls.py里加下映射:
# 记得要
# from django.views.generic import RedirectView
path('', RedirectView.as_view(url='user/login.html')),
总的项目的urls.py里,我们也需要进行修改:
这样我们直接请求 http://127.0.0.1:8000/ ,跳转到登录页面:
点击用户注册,跳转到注册页面:
配置自定义用户模型
在项目开发过程中,我们发现Django默认的admin系统中的用户模型无法充分满足特定的业务需求。为了实现对用户属性的自定义扩展,我们决定采用继承AbstractUser类的方式来创建自定义用户模型。这种方案既能保留Django内置的用户认证功能,又可以根据实际业务需求灵活地添加所需的字段和功能,为系统的用户管理提供更完善的支持。
user / models.py:
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class MyUser(AbstractUser):
name = models.CharField('姓名', max_length=50, default='匿名用户')
introduce = models.TextField('简介', default='暂无介绍')
company = models.CharField('公司', max_length=100, default='暂无信息')
profession = models.CharField('职业', max_length=100, default='暂无信息')
address = models.CharField('住址', max_length=100, default='暂无信息')
telephone = models.CharField('电话', max_length=11, default='暂无信息')
wx = models.CharField('微信', max_length=50, default='暂无信息')
qq = models.CharField('QQ', max_length=50, default='暂无信息')
avatar = models.ImageField('头像', blank=True, upload_to='avatar/')
# 设置返回值
def __str__(self):
return self.name
media目录下新建avatar目录,用于存储图像
settings.py:
# 配置自定义用户模型MyUser
AUTH_USER_MODEL = 'user.MyUser'
makemigrations生成迁移文件;migrate执行迁移文件;
启动报错,缺少pillow库,我们安装下
pip install pillow==11.0.0
再执行:
makemigrations
migrate
migrate执行后,生成了所有表,包括admim系统的用户表
用户注册功能实现
本功能实现用户注册的后台逻辑处理流程如下:当客户端发起POST请求时,服务端通过request.POST获取username、password、password2三个表单参数。系统将依次执行以下验证步骤:
- 用户唯一性校验:通过User.objects.filter(username=username).exists()查询数据库,若存在重复用户名则返回错误提示
- 密码一致性验证:比对password与password2参数,若不一致则中断注册流程
- 数据持久化存储:使用User.objects.create_user(**d)方法创建用户记录,其中字典d通过双星号运算符解包键值对,自动匹配模型字段与表单参数
- 模板数据绑定:通过render(request, 'register.html', locals())将当前作用域的变量(如用户输入值、错误信息等)注入模板上下文,实现页面元素的动态渲染。
在user/views.py文件中写入如下代码:
from django.contrib.auth import logout
from user.models import MyUser
def register(request):
"""
用户注册
:param request:
:return:
"""
username = request.POST.get('username', '')
password = request.POST.get('password', '')
password2 = request.POST.get('password2', '')
if MyUser.objects.filter(username=username):
info = '用户已存在'
elif password2 != password:
info = '两次密码输入不一致'
else:
d = {
'username': username, 'password': password,
'is_superuser': 1, 'is_staff': 1
}
user = MyUser.objects.create_user(**d)
user.save()
info = '注册成功,请重新登录'
logout(request) # 清除登录信息
return render(request, 'register.html', locals())
我们再配置user/urls.py映射:
# 用户注册请求
path('register', register, name='userRegister'),
# 记得在代码开头加上
# from user.views import register
测试一下:
可以看到,密码是加密的。
用户登录功能实现
用户认证功能实现技术方案:
本系统采用Django认证框架实现用户登录流程,具体执行逻辑如下:
-
凭证获取与初步验证
通过request.POST获取username和password参数,执行User.objects.filter(username=username).exists()进行用户存在性校验 -
身份认证管道
使用authenticate(request, username=username, password=password)构建认证用户对象,该方法自动完成:
密码哈希值比对
用户模型关联校验
CSRF令牌验证
3. 账户状态验证
对认证成功的用户对象(user)进行激活状态检测,通过user.is_active属性判断账户可用性
4. 会话管理机制
通过auth.login(request, user)方法建立持久化会话:
生成session_key存入数据库
设置sessionid cookie
注册用户对象至请求上下文
5. 异常处理规范
针对不同失败场景返回对应错误类型:
- 用户不存在:提示"用户不存在,请注册"
- 账号或密码错误:提示"用户名或者密码错误!"
已注册账号:xlsss 密码:123456
user/views.py增加如下代码:
from django.contrib.auth import authenticate, login as auth_login
def login(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
if MyUser.objects.filter(username=username):
user = authenticate(username=username, password=password)
if user:
if user.is_active:
# django.contrib.auth.login(request, user)
auth_login(request, user)
print("登录认证成功,跳转到博客主页")
else:
errorinfo = '用户名或者密码错误!'
else:
errorinfo = '用户不存在,请注册'
return render(request, 'login.html', locals())
user/urls.py增加如下代码:
# 用户登录请求
path('login', login, name='userLogin'),
跳转成功!
后续
持续更新中。。。