前言
这个django的博客已经不再更新了。因为维护更新起来太过麻烦(就是懒)
项目链接
源码放这了哈!
github仓库地址: https://github.com/dajavv/DjangoBolg
使用工具
-
- PyCharm 2023.1
-
- python3.10 版本
Hexo框架
在使用了一段时间的Hexo博客后,对该框架的感受:
优势
-
- 具有很多的主题,每一款都非常好看
-
- 强大的模板语法
-
- 生态完善,具有大量插件,比如:bilibili视频的小卡片、全局搜索、评论模块
劣势
-
- 部署不便,要使用命令导入静态文件后部署到github,国内登入网络不稳定(痛点)
-
- 维护较为困难
-
- 加载缓慢
-
- 缺少后端进行管理
-
- 无法对整体文章进行搜索(可以通过插件实现,比较麻烦,不考虑)
-
- 缺少与访客的互动
-
- 缺少对访客数据的记录
解决问题
对于这些问题我决定对博客进行重构,让博客具有更强的功能,我计划对Hexo框架所创建的博客进行重构。 在重构的同时对django框架进行学习
功能
-
- (√)导航栏
-
- (√)白天黑夜切换
-
- (√)分类
-
- (√)归档
-
- (√)标签分类
-
- (√)最新文章
-
- (√)后台发布公告
-
- (√)后台发布文章
-
- (√)后台管理
-
- (×)代码高亮
-
- ## 新计划
-
- (×)访客数据统计
-
- (×)全站搜索
-
- (×)音乐盒
流程
-
- 使用PyCharm创建Django项目,conda创建虚拟环境python3.10,导包
-
- 创建app命名为post
-
- settings中添加post应用
-
- 对原html静态文件进行导入拆分,制作基础模版
-
- 配置路由,创建视图函数,
-
- 检查是否能正常运行显示
-
- 配置数据库,创建数据表,对需要进行动态更新的数据创建数据表
-
- 将要管理的数据表添加到admin文件中
-
- 使用django的模版语法将要动态改变的数据放到html中
-
- 完善功能(分页、分类、归档、标签归类、最新文章……)
-
- 对网页进行测试
-
- 完成
开始
创建虚拟环境
其中的python为python.exe的路径
python -m pip install virtualenv # 安装虚拟环境库
virtualenv env # 创建虚拟环境
env\Scripts\activate # 进入虚拟环境
创建应用
打开控制台 (可以使用使用ctrl+alt+R快捷键打开manage专属控制台)
django-admin startproject 项目名
cd 项目名
python manage.py startapp app名
在settings.py文件INSTALLED_APPS配置项中添加post应用
INSTALLED_APPS = [
...
'post' #添加app
]
创建基础模板
对博客网页进行拆分 组件化拆分利于更新与维护,
-
- 基础模版
-
- 横幅
-
- 导航栏
-
- 侧边栏
-
- 介绍卡片
-
- 公告
-
- 分类
-
- 标签
-
- 归档
-
- 最新文章
-
- 底部页脚
-
- 侧边栏
-
- 基础模版
-
- 内容模块
-
- 分类
-
- 归档
-
- 标签
-
- 文章选项卡
-
- 关于
-
- 内容模块
基础模板
在基础模版中,多为静态不需要改动的页面部分,将他们封装在根目录的templates模版文件夹中
{% include 'banner.html' %} #横幅
<div id="main-grid" class="shadow">
{% include 'head.html' %} #导航栏
{% include 'right.html' %} #侧边栏
{% block main %} <!--与app中的index相连--> #文章选项卡片
{% endblock %}
{% include 'footer.html' %} #底部页脚
<div class="back-to-top-wrapper"><!--回到顶部按键-->
<button id="back-to-top-btn" class="back-to-top-btn" onclick="topFunction()"> #回到顶部的按钮
<span class="material-symbols-rounded">keyboard_arrow_up</span>
</button>
</div>
</div>
Django模版语法
{% include 'banner.html' %} #引入一部分html代码
{% block main %}...{% endblock %} #页面的动态部分,后面写的会覆盖同名的代码块,在基础模版中用于占位
{% extends 'base.html' %} #继承基础模版中的静态部分
{% block title %}网页标题{% endblock %} #指定该网页的标题
{% for i in 传递过来的相应数据 %}...{% endfor %} #和python中的for相似
{% if 判断条件 %}{% elif 判断条件 %}{% else %}{% endif %} #条件加载
静态文件路径配置
在settings配置文件中添加STATICFILES_DIRS配置
这里是模版的配置,设置优先在根目录中寻找templates模版文件夹
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates']
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'post.mycontextprocessor.getRightInfo' # 引入分类,路径是app中的类中的函数
],
},
},
]
路径配置
只有配置了静态文件在html文件中才能正确找到静态的文件
在settings配置文件中
STATIC_URL = 'static/' #根目录下的static文件夹
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static', 'css'), # BASE_DIR根目录,这条配置会指定对寻找文件的路径,这里我让他去寻找static文件夹中的css文件夹
os.path.join(BASE_DIR, 'static', 'js'),
os.path.join(BASE_DIR, 'static', 'fontawesome'),
]
在html中
<link rel="stylesheet" href="/static/style.css">
其中的href路径,相当于
static/css/style.css
<script src="/static/bundle.js"></script>
路由配置
在项目名的文件夹中的urls文件中进行配置 在这里我将路由导向了app中的urls文件
urlpatterns = [
path('admin/', admin.site.urls), #django自带的后台管理面板
path('', include('post.urls')), # 将路由导向app中的urls文件,核心路由配置
]
app中的路由配置
导入视图类来自app中的views文件 导入路由url配置类
from post import views #app中的视图类
from django.urls import path, re_path #
在这里的路由配置方法主要有两种
as_view的作用
as_view()是Django中用于将类视图转换为可调用的视图函数的方法。 在Django中,类视图是基于类的视图的一种方式。类视图通过继承Django提供的一些基类,可以更清晰、灵活地定义视图逻辑,并提供了许多便捷的方法和属性。但在URL配置中,我们需要将视图映射到具体的URL路径上,这就需要将类视图转换为可调用的函数形式。 .as_view()方法就是用来实现这个转换的。当在URL配置中定义一个类视图时,我们通常会使用.as_view() 方法将其转换为可调用的视图函数,并将其作为参数传递给URL配置。
path(常用):
<>中会匹配一个具体的数据,这个数据将会作为参数传递到视图函数当中
path('page/<int:num>/', views.IndexViex.as_view(), name='页面'), #路由配置
#参数一:路由将要拼接的url
#参数二:指定路由的视图函数
#参数一:别名
#views视图函数
def get(self, request,num=1): #num设置了默认值
re_path(使用正则表达式进行匹配):
用r''来标识正则表达式的文字, ^$匹配开头导结尾 (page/.?/)? page/后面匹配任意文本(除换行符),匹配多次,?可有可无,()?该段文本可有可无 post/ 必须存在的路径 (?P\d+)/ 这里使用了django中的专属语法, <>中匹配一个数据,这个数据将会作为参数传递到视图函数当中
re_path(r'^(page/.*?/)?post/(?P<postid>\d+)/$', views.DetailViex.as_view(), name='文章'),
视图函数的创建
在viexs文件中创建与视图一一应的视图类,同时必须继承View视图类 get方法,因为是类方法索引必须有self,同时,必须有一个名为request消息的参数,这个参数承载了请求者的信息,我们可以对他进行响应处理,在这个方法中将会接收访问该URL时候的get请求,get请求会在进入url时发起( get请求也可以手动发起),多用于获取数据
class IndexViex(View):
def get(self, request):
return render(request, 'index.html', {})#向浏览器返回视图,响应数据
#第一个参数是请求消息
#第二个参数是指定所要显示的页面,这里是名为index的html网页文件返回到浏览器,(这里会在前面我们在settings中配置的模版文件夹中自动寻找,当根目录中的模版文件夹中没有该html文件时才会来到app的模版文件夹中寻找)
#第三个参数是响应数据,一般为将要加载到网页中的动态数据,会在html中使用django模版语法进行加载
启动程序
若前面的配置的没有问题,这时候已经可以启动项目查看网页的大体形态了 这时候的页面还是静态的 打开控制台输入启动命令,启动程序
cd 项目文件夹
python manage.py runserver --post=8000
动态数据
数据库配置
在settings文件中设置数据库
默认数据库SQLite,SQLite 是一个轻量级的关系型数据库管理系统,它以文件形式存储数据库,并且不需要独立的数据库服务器进程。这使得 SQLite 在开发和测试阶段非常方便,因为它不需要额外的数据库服务器安装和配置。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # 数据库引擎
'NAME': BASE_DIR / 'db.sqlite3', # 路径
}
}
mysql数据库的配置方法
使用mysql需要额外导入一个包
pip install mysqlclient
导入后对settings中的DATABASES进行配置
DATABASES = { # 配置数据库
'default': {
'ENGINE': 'django.db.backends.mysql', # mysql数据库引擎
'NAME': 'boke1', # 数据库名
'USER': 'root', # 账号
'PASSWORD': '123456', # 密码
'HOST': '127.0.0.1', # url
'PORT': '3306', # 端口号
}
}
models模型配置
需要我们导入模型库,创建自己的模型类。 在这里写的代码会被转化为sql语句在数据库中创建数据表
from django.db import models#导入模型库
# Create your models here.
class Category(models.Model):#继承于models.Model
cname = models.CharField(max_length=30, unique=True, verbose_name=u'类别名称')
def __unicode__(self):
return u'<Category:%s>' % self.cname
class Meta:
db_table = 't_category' # 表名
verbose_name_plural = u'类别'
class Tag(models.Model):
tname = models.CharField(max_length=20, unique=True, verbose_name=u'标签')
def __unicode__(self):
return u'<Tag:%s>' % self.tname
class Meta:
db_table = 't_tag'
verbose_name_plural = u'标签'
from ckeditor_uploader.fields import RichTextUploadingField
class Post(models.Model):
title = models.CharField(max_length=100, unique=True, verbose_name=u'标题')
desc = models.CharField(max_length=200, verbose_name=u'简介')
content = RichTextUploadingField(null=True, blank=True, verbose_name=u'内容') # 引入控件
created = models.DateTimeField(auto_now_add=True, verbose_name=u'发帖时间') # 当前时间
modified = models.DateTimeField(auto_now=True, verbose_name=u'修改时间') #
isdelete = models.BooleanField(default=False, verbose_name=u'是否删除')
category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name=u'所属类别')
tag = models.ManyToManyField(Tag, verbose_name=u'所属标签')
words = models.CharField(max_length=15, verbose_name=u'字数')
photos = models.CharField(max_length=300, verbose_name=u'封面图片')
def __unicode__(self):
return u'<Post:%s>' % self.title
class Meta:
db_table = 't_Post'
verbose_name_plural = u'帖子'
class AdminUser(models.Model):
aname = models.CharField(max_length=20, unique=True, verbose_name='名字')
avatar = models.CharField(max_length=200, unique=True, verbose_name='头像')
signature = models.CharField(max_length=100, unique=True, verbose_name='签名')
announcement = models.CharField(max_length=200, unique=True, verbose_name='公告')
steam = models.CharField(max_length=200, unique=True, verbose_name='steam链接')
bilibili = models.CharField(max_length=200, unique=True, verbose_name='bilibili链接')
github = models.CharField(max_length=200, unique=True, verbose_name='github链接')
about = models.CharField(max_length=1000, null=True, blank=True, verbose_name=u'关于')
banner = models.CharField(max_length=200, unique=True, verbose_name='横幅')
def __unicode__(self):
return u'<AdminUser:%s>' % self.aname
class Meta:
db_table = 't_AdminUser'
verbose_name_plural = u'管理用户信息'
verbose_name="名字"#相当于别名会在admin管理界面中使用
def __unicode__(self):
return u'<Post:%s>' % self.title #该数据表类在admin管理界面中的标题
数据字段的定意
aname = models.CharField(max_length=20, unique=True, verbose_name='名字')#字符类型字段,max_length最大长度20,unique不可重复,
created = models.DateTimeField(auto_now_add=True, verbose_name=u'发帖时间') # 时间类型字段,auto_now_add自动添加会自动记录当前时间
isdelete = models.BooleanField(default=False, verbose_name=u'是否删除')#布尔类型字段
category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name=u'所属类别')#外键
tag = models.ManyToManyField(Tag, verbose_name=u'所属标签')#多对多类型字段
content = RichTextUploadingField(null=True, blank=True, verbose_name=u'内容') # 这里使用了引入的控件库,这个控件库可以使用makdown语法对数据进行编辑
迁移文件
完成数据库的配置后,输入命令创建数据库的迁移文件,执行迁移文件
python manage.py makemigrations #创建迁移文件
python manage.py migrate #执行迁移文件
这时候在根目录下就会生成一个db.sqlite3数据库文件 下载驱动,对数据库进行连接
后台管理系统
这里使用django自带的管理系统 在应用的admin文件夹中配置
from __future__ import unicode_literals
from django.contrib import admin
from .models import *
# Register your models here.
admin.site.register(Category) # 注册到admin控制面板中
admin.site.register(Tag)
admin.site.register(Post)
admin.site.register(AdminUser)
并且在urls配置中
path('admin/', admin.site.urls),
添加管理用户
对数据库中的auth_user表添加默认管理员账户(我用的是PyCharm右侧的数据库栏手动添加的数据)
python manage.py collectstatic --noinput
python manage.py compress --force
登入管理页面http://127.0.0.1:8000/admin/ 输入你所设置的后台管理账户 添加数据库基础测试数据 在admin中我们可以对配置的数据库数据进行可视化管理
404跳转
在urls配置中添加这一条代码 这行代码会读取settings中的DEBUG配置(该配置为TRUE时),当我们访问不存在的网址时,就会进行跳转
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
视图
在views文件中,我们需要书写代码逻辑对前端的数据进行响应 对库进行导入
import math#数学库
from django.core.paginator import Paginator #分页器
from django.http import HttpResponse, HttpResponseRedirect #响应
from django.shortcuts import render, redirect #渲染,重定向
from django.urls import reverse
from django.views import View # 导入
from post.models import * #定义的全部模型类
类继承于View,定义视图类。 这是主页的响应类,这里使用render渲染视图
render(request,'要渲染的html文件,响应数据')
首页
渲染index.html文件 请求中的num会从url中得到 使用Paginator分页器,结果返回数据,postList当前页码的数据,page_list页面列表,currentNum当前页码 通过构建一个最大为9个索引的码列表,根据当前页面不断更改页码列表
# Create your views here.
class IndexViex(View):
def get(self, request, num=1):
num = int(num) # 转型
postList = Post.objects.all().order_by('-created') # 查询所有的帖子信息,按照发帖时间排序
page_obj = Paginator(postList, 10) # 创建分页器对象,每一页显示一条记录
page_post = page_obj.page(num) # 获取num页的数据
begin = int(num - math.ceil(10.0 / 2)) # 页码num在数组中的相对位置
# print(begin) # [-4,-3,-2,-1,0,1,2,3,4] 页面的相对位置?
if begin < 1: # 当前位置在1(数组后半段)之前,
begin = 1 # 将当前位置变为1
end = begin + 9
if end > page_obj.num_pages:
end = page_obj.num_pages # 获取页码总数(最大页码)
if end < 10: #
begin = 1
else:
begin = end - 9
page_list = range(begin, end + 1) # 构造一个最大为10的数组,并且里面的数字随着页面num的增大而变换,
return render(request, 'index.html', {'postList': page_post, 'page_list': page_list, 'currentNum': num})
文章
渲染detail.html文件 在这里会通过postid帖子id进行查询获得帖子的内容数据
class DetailViex(View):
def get(self, request, postid): # 文章内容
postid = int(postid)
post_obj = Post.objects.get(id=postid) # 条件查询id
return render(request, 'detail.html', {'post_obj': post_obj})
分类
通过导入的模型类查询该类别的文章,显示在同一页面上
def getPostByCid(request, categorie): # 分类
# categoryid = int(category)
c_post = Post.objects.filter(category__cname=categorie) # 查询类别下的文章
# print(c_post)
return render(request, 'postlist.html', {'categorie': categorie, 'c_post': c_post})
归档
查询全部
def getPostArchives(request):
c_post = Post.objects.all() # 查询全部
return render(request, 'archives.html', {'c_post': c_post})
标签
根据tag查询文章
def getPostTags(request, tag):
c_post = Post.objects.filter(tag__tname=tag) # 根据标签名查询
return render(request, 'tags.html', {'tag': tag, 'c_post': c_post})
关于
读取关于页面的数据表,返回页面信息
def About(request):
post_obj = AdminUser.objects.all()[0]
return render(request, 'about.html', {'post_obj': post_obj})
404跳转
# def page_not_found(request, exception): # 全局404处理函数
# return redirect('11') # 重定向回到主页
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://cpxigxs.cn/2024/04/20/90/
共有 0 条评论