Django项目 ------支持Markdown语法和代码高亮的个人博客系统

文章目录

  • 支持Markdown语法和代码高亮的个人博客系统
    • 零、Django
      • 面视问 :站点有没有做防护,遇到什么问题,怎么解决?
    • 一、项目介绍
      • 1.本文采用的技术
      • 2.本文实现的功能
      • 3.系统环境
    • 二、项目准备
      • 1.建立 Django 工程
      • 2.项目配置
      • 3.创建admin后台管理的用户及测试
      • 4.创建blog应用 及 注册应用
    • 三、项目
    • 第一步 数据库模型的创建
      • 1.数据库需求分析
      • 2.博客模型代码
      • 3.数据库迁移
    • 第二步 Django Admin 后台发布文章
      • 1.在 Admin 后台注册模型
      • 2.定制 Admin 后台
      • 3.测试
    • 第三步 Django 博客首页 和 详情页
      • 1.创建一个 urls.py 文件
      • 2.编写 views.index 和views.detail 视图函数
      • 3.把 blog 应用下的 urls.py 文件包含到BlogProject\urls.py 里去
      • 4.html测试模板
      • 5.在 settings.py 文件里设置 静态文件static和模板templates文件
      • 6.编写前端html完整模板
        • (1)处理静态文件static和模板templates文件
        • (2)模板的继承
      • 7.前端页面完整代码
      • 8. 浏览器端项目测试
    • 第四步 上传gitee码云
      • 1. 上传代码
      • 2.重新输入账号密码的代码
    • 第五步 支持 Markdown 语法
      • 1.安装 Python Markdown
      • 2.在 detail 视图中渲染 Markdown
      • 3.使用 safe 过滤器 解除Django 转义
    • 第六步 代码高亮
      • 1.安装 Pygments
      • 2.引入样式文件
      • 3.发现代码依然没有高亮,依次检查以下步骤
        • 4.浏览器端测试
    • 第七步 页面侧边栏
      • 1.内置的模板标签
      • 2.自定义模板标签
        • (1)模板标签目录结构
        • (2)最新文章模板标签
        • (3)归档模板标签
        • (4)分类模板标签
        • (5)标签云模板标签
      • 3.使用自定义的模板标签
      • 4.测试
    • 第八步 分类与归档完善跳转连接
      • 1.配置url
      • 2.编写视图函数:
      • 3.修改相应的模板
      • 4.测试
    • 第九步 统计各个分类下的文章数
      • 1. `annotate` 方法
      • 2.模板中引入
    • 第十步 统计文章阅读量
      • 1.增加新字段
      • 2.增加模型方法
      • 3.迁移数据库
      • 4.修改视图函数
      • 5.在模板中显示阅读量
      • 6.浏览器端测试
    • 第十一步 修改 首页、关于、博客、联系 的跳转链接
    • 十二步 将代码提交到gitee
    • 十三步 部署

支持Markdown语法和代码高亮的个人博客系统

完整代码在:https://gitee.com/dadadaliuliuliiu/BlogProject

零、Django

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第1张图片
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第2张图片

面视问 :站点有没有做防护,遇到什么问题,怎么解决?

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第3张图片

一、项目介绍

随着互联网的飞速发展,让Internet应用在全球范围内日趋普及,当今社会也正快速向信息化社会发展,开发个人博客有着非常重要的意义。

1.本文采用的技术

本系统采用 Django 技术,后台开发工具为Pycharm ,前台开发工具为Pycharm ,数据库采用 MySQL 来进行开发。

2.本文实现的功能

  • 该文主要包含游客前台阅读、留言博文功能。后台用户登录、注册、管理个人博客, 精确地记录一篇文章的阅读量, 自动生成文章摘要等功能。
  • 为了让博客文章具有良好的排版,显示更加丰富的格式,支Markdown 语法和代码高亮。 这种博客是一种可以快速发布并且及时更新信息的网站,用户可以简洁快速地完成博客的书写、公布和更新,很好实现用户体验,大大提高了用户的工作效率。

3.系统环境

  • python3.7
  • Django2.2

二、项目准备

1.建立 Django 工程

新建一个django项目自动生成的目录:
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第4张图片

2.项目配置

设置中文和时区
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第5张图片
浏览器端测试
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第6张图片

3.创建admin后台管理的用户及测试

(base) F:\ziliao\python_kaifa\my_code\12_django项目\BlogProject>python manage.py createsuperuser  #创建后台管理的用户
用户名 (leave blank to use 'daliu'): admin
电子邮件地址: admin@qq.com
Password:westos123
Password (again):

(base) F:\ziliao\python_kaifa\my_code\12_django项\BlogProject>python manage.py runserver


浏览器端测试:
登陆刚才创建的用户,进入后台管理:
admin
westos123
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第7张图片

4.创建blog应用 及 注册应用

blog 是整个BlogProject项目的一个功能

(base) F:12_django项目\BlogProject>python manage.py startapp blog

目录中出现blog应用

在BlogProject里注册
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第8张图片
以上是项目准备

三、项目

第一步 数据库模型的创建

1.数据库需求分析

博客最主要的功能就是展示我们写的文章,它需要从某个地方获取博客文章数据才能把文章展示出来,通常来说这个地方就是数据库。我们把写好的文章永久地保存在数据库里,当用户访问我们的博客时,Django 就去数据库里把这些数据取出来展现给用户。

数据库存储的数据其实就是表格的形式。
存储博客文章的数据库表如下所示:
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第9张图片
分析一下我们就会发现一个问题,这 3 篇文章的分类和标签都是相同的,这会产生很多重复数据,当数据量很大时就浪费了存储空间。
我们把分类和标签提取出来,做成单独的数据库表,再把文章和分类、标签关联起来。

下面分别是分类和标签的数据库表:
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第10张图片

2.博客模型代码

#blog/models.py

from datetime import datetime
from django.db import models

# Create your models here.

class Category(models.Model):
    """分类表"""
    #一个类就是一个数据库表
    # Django的数据库模型默认会添加id作为主键
    name=models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Tag(models.Model):
    """标签表"""
    name=models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Post(models.Model):
    """ 博客表 """
    # 文章标题
    title = models.CharField(max_length=70)
    # 文章正文,我们使用了 TextField。
    body = models.TextField()
    # 这两个列分别表示文章的创建时间和最后一次修改时间,存储时间的字段用 DateTimeField 类型。
    # auto_now=True,每次对像更新时更新时间。auto_now_add=True对象第一次创建时设置的时间
    created_time = models.DateTimeField(auto_now_add=True)
    modified_time = models.DateTimeField(auto_now=True)
    # 文章摘要,可以没有文章摘要,但默认情况下 CharField 要求我们必须存入数据,否则就会报错。
    # 指定 CharField 的 blank=True 参数值后就可以允许空值了。
    excerpt = models.CharField(max_length=200, blank=True)
    # on_delete=False在Django1.x版本默认是不级联删除的,可以不做设置. Django2.x一定要自 行指定.
    category = models.ForeignKey(Category, on_delete=False)
    # 多对多关系。 blank=True标签可以不做设置
    tags = models.ManyToManyField(Tag, blank=True)
    # 文章作者,这里 User 是从 django.contrib.auth.models 导入的。
    # 因为我们规定一篇文章只能有一个作者,而一个作者可能会写多篇文章,因此这是一对多的关联关 系,和 Category 类似。
    # author = models.ForeignKey(User)

    def __str__(self):
        return self.title

3.数据库迁移

数据库做了改变,就要写入数据库,所以要产生一个迁移文件

(base) F:12_django项目\BlogProject>python manage.py makemigrations  #生成迁移脚本
Migrations for 'blog':
  blog\migrations\0001_initial.py
    - Create model Category
    - Create model Tag
    - Create model Post

(base) F:\12_django项目\BlogProject>python manage.py migrate  # 将迁移信息写入数据库
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying blog.0001_initial... OK

第二步 Django Admin 后台发布文章

1.在 Admin 后台注册模型

要在后台注册我们自己创建的几个模型,这样 Django Admin 才能知道它们的存在,注册非常简单,只需要在 blog\admin.py 中加入下面的代码:

blog 是整个BlogProject项目的一个功能 ,Post, Category, Tag是一个类,他们分别对应一个数据库表,表示博文的正文、分类以及标签信息。因此,要在后台注册我们自己创建的几个模型,这样 Django Admin 才能知道它们的存在

# blog/admin.py

from django.contrib import admin
from blog.models import Post, Category, Tag

admin.site.register(Post)
admin.site.register(Category)
admin.site.register(Tag)

运行程序
访问网址 http://127.0.0.1:8000/admin/ 测试是否设置成功?
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第11张图片

2.定制 Admin 后台

在 admin post 列表页面,我们只看到了文章的标题,但是我们希望它显示更加详细的信息,这需要我们来定制 Admin 了,在 admin.py 添加如下代码:

from django.contrib import admin
from blog.models import Post, Category, Tag

class PostAdmin(admin.ModelAdmin):
    list_display = ['title', 'created_time', 'modified_time', 'category']
    list_display_links = ['title', 'created_time']
    search_fields=['title']  # 以title搜索
    list_per_page = 5  #分页

# 把新增的 PostAdmin 也注册进来
admin.site.register(Post,PostAdmin)
admin.site.register(Category)
admin.site.register(Tag)

3.测试

创建博客信息并保存 来测试
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第12张图片
只显示标题的
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第13张图片
有详情和分页
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第14张图片

第三步 Django 博客首页 和 详情页

1.创建一个 urls.py 文件

当用户在浏览器端输入一个url时,首先访问这里的代码

  • 首页视图匹配的 URL 去掉域名后其实就是一个空的字符串。
  • 对文章详情视图而言,每篇文章对应着不同的 URL。
    当用户访问 <网站域名>/post/1/ 时,显示的是第一篇文章的内容,
    当用户访问 <网站域名>/post/2/ 时,显示的是第二篇文章的内容。这里数字代表了第几篇文章,也就是数据库中 Post 记录的 pk(id) 值。下面依照这个规则来绑定 URL 和视图:

首先在 blog 应用的目录下创建一个 urls.py 文件, 在 blog\urls.py 中写入这些代码:

# blogs/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
	#当用户在浏览器端输入一个url,没有开头也没有结尾时,比如:http://127.0.0.1:5000,去寻找index首页的视图函数,
    url(r'^$', views.index, name='index'),
    # 正则表达式
    # ^: 以什么开头, $是以什么结尾。 [0-9]指单个数字, +代表前面的字符出现1次或者多次。
    # [0-9]+: 1, 2, 2344, 78888,
    # (?P[0-9]+) 关键字匹配
    # /post/1/   ====> 1满足正则规则的, 将pk=1
    url(r'^post/(?P[0-9]+)/$', views.detail, name='detail'),
]

为了方便地生成上述的 URL,我们在 Post 类里定义一个 get_absolute_url 方法,注意 Post 本身是一个 Python 类,在类中我们是可以定义任何方法的。

# blog/models.py

class Post(models.Model): 
	...
    def __str__(self):
        return self.title

    # 自定义 get_absolute_url 方法
    # 记得从 django.urls 中导入 reverse 函数
    def get_absolute_url(self):
        # reverse相当于Flask里面的url_for, 根据视图函数名称反向获取对应的路由地址.
        # /post/1/
        return reverse('detail', kwargs={'id': self.id})

2.编写 views.index 和views.detail 视图函数

第二步编写我们的 视图函数,按照惯例视图函数定义在 views.py 文件里:

  • 捕获的文章 id(也就是 pk,这里 pk 和 id 是等价的)。
  • get_object_or_404 方法,其作用就是当传入的 pk 对应的 Post 在数据库存在时,就返回对应的 post ,如果不存在,就给用户返回一个 404 错误,表明用户请求的文章不存在。
# blog/views.py

from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from blog.models import Post


def index(request):
    posts = Post.objects.all()
    
	#在这里视图函数Django和flask不一样的地方是形式和传参,
	# context :传的参数以字典的形式
    return render(request, 'blog/index.html', context={
        'posts': posts
    })

def detail(request, id):
	#Post:是models中的Post类对象
    post = get_object_or_404(Post, id=id)
    return render(request, 'blog/detail.html', context={'post': post})
    
"""
flask 中的views与django views视图函数对比
@app.route('/')
def index():
    return 'xxxx'
    return  render_template('xxxx.html', name=name, welcome=welcome)
    
@app.route('/post/'/) 
def detail(id):
    return id   
    

"""

3.把 blog 应用下的 urls.py 文件包含到BlogProject\urls.py 里去

最后,我们前面建立了一个 urls.py 文件,并且绑定了 URL 和视图函数 index ,但是 Django 并不知道。Django 匹配 URL 模式是在BlogProject\ 目录(即 settings.py 文件所在的目录)的 urls.py 下的,所以我们要把 blog 应用下的 urls.py 文件包含到 BlogProject\urls.py 里去,打开这个文件看到如下内容:

# BlogProject\urls.py
from django.conf.urls import url
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'', include('blog.urls')),
]

4.html测试模板

在项目根目录(即 manage.py 文件所在目录)下建立一个名为 templates 的文件夹,用来存放我们的模板。
在 templates\ 目录下建立一个名为 blog 的文件夹,用来存放和 blog 应用相关的模板。
在 templates\blog 目录下建立一个名为 index.html 的文件

# templates/blog/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎来到博客首页</h1>
</body>
</html>
# templates/blog/detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ posts.title }}
{{ posts.created_time }}
{{ posts.modified_time }}
{{ posts.body }}

</body>
</html>

5.在 settings.py 文件里设置 静态文件static和模板templates文件

在BlogProject/ settings.py 找到 TEMPLATES 和 STATIC_URL 选项,编写:

# blogproject/settings.py 
TEMPLATES = [ 
	{ 
		... 
		'DIRS': [os.path.join(BASE_DIR, 'templates')], 
		... 
	}, 
]


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/

STATIC_URL = '/static/'

# 静态文件存放路径
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

浏览器端访问详情页的内容
在这里插入图片描述

6.编写前端html完整模板

项目使用了从网上下载的一套博客模板。Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第15张图片
当我们点击首页文章的标题或者继续阅读按钮后就会跳转到该篇文章对应的详情页面了。然而如果你尝试跳转到详情页后,你会发现样式是乱的。由于我们是直接复制的模板,还没有正确地处理静态文件。
你会发现在任何页面都是需要引入这些静态文件,如果每个页面都要修改会很麻烦,而且代码都是重复的。下面就介绍 Django 模板继承的方法来帮我们消除这些重复操作。

(1)处理静态文件static和模板templates文件

项目使用了从网上下载的一套博客模板。这里面除了 HTML 文档外,还包含了一些 CSS 文件和JavaScript 文件以让网页呈现出我们现在看到的样式。同样我们需要对 Django 做一些必要的配置,才能让 Django 知道如何在开发服务器中引入这些 CSS 和 JavaScript 文件,这样才能让博客页面的 CSS样式生效。

在 BlogProject应用下建立一个 static 文件夹。将 CSS 和 JavaScript 等静态文件复制到static目录中。
并将首页index.html和详情页detail.html复制到templates/blog中
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第16张图片
修改静态文件的链接目录

{% load staticfiles %} 

# 两种方式任选一种 
<link rel="stylesheet" href="{% static 'css/pace.css' %}"> 
<link rel="stylesheet" href="/static/css/pace.css">

这里选择第二种
这里是static不是stasic

在这里插入图片描述
在这里插入图片描述
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第17张图片

(2)模板的继承

index.html 文件和 detail.html 文件除了 main 标签包裹的部分不同外,其它地方都是相同的,我们可以把相同的部分抽取出来,放到 base.html 里。首先在 templates\ 目录下新建一个base.html 文件。把 index.html 的内容全部拷贝到 base.html 文件里,然后删掉 main 标签包裹的内容。

base.html文件修改如下:

顶行加载静态文件
首页和详情页不同之处:title处,标题不一样,所以空出来
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第18张图片
body处,导航栏一样,不用修改
body处,导航栏下面左边部分不同,空出来;右边部分,首页最上方多了一块内容最新文章,空出来
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第19张图片

index.html文件修改如下:

我们在文件最顶部使用 {% extends ‘base.html’ %} 继承 base.html ,这样就把 base.html 里的代码继承了过来,
在{% block title %}{% endblock %}包裹的地方填上 index 页面的标题
在 {% block main %}{% endblock %} 包裹的地方填上 index 页面应该显示的内容
在{% for post in posts %}{% endfor %}包裹的地方填上 index 页面应该显示的博客正文信息,用for循环来访问,代码更简洁.

用如下(类似jinja2)的语法,在前端获取后端的数据。
{% for post in posts %}{% endfor %} # posts:首页的视图函数传进来的posts对象
在这里插入图片描述
detail.html文件修改如下:

在{% block title %}{% endblock %}中填充标题内容
在 {% block main %}{% endblock main %} 里填充 detail.html 页面应该显示的内容,
在main中加入获取后端数据的代码,让其显示文章的实际数据:
在 {% block aside%}{% endblock aside%} 中填写 base.html 中没有的目录部分的内容。不过目前的目录只
是占位数据,我们在以后会实现如何从文章中自动摘取目录。

7.前端页面完整代码

https://gitee.com/dadadaliuliuliiu/BlogProject/tree/master/templates

8. 浏览器端项目测试

访问主页
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第20张图片
点击博客标题进入博客内容
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第21张图片

第四步 上传gitee码云

1. 上传代码


(base) F:\ziliao\python_kaifa\my_code\11_Django项目\BlogProject>git add *
(base) F:\ziliao\python_kaifa\my_code\11_Django项目\BlogProject>git commit 
(base) F:\ziliao\python_kaifa\my_code\11_Django项目\BlogProject>git push origin master
Username for 'https://gitee.com': dadadaliuliuliiu
Password for 'https://[email protected]':

2.重新输入账号密码的代码

每次push或者pull的时候都要求输入账号和密码

git config --global credential.helper store

git本地仓库用户名和密码设置

git config --global user.name "Your Name"
git config --global user.email “email@example.com”

git提交到远程地址,
.git/config目录里是配置文件,如果要修改上传地址,在这个文件中修改
在这里插入图片描述
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第22张图片

第五步 支持 Markdown 语法

为了让博客文章具有良好的排版,显示更加丰富的格式,我们使用 Markdown 语法来书写我们的博文。
Markdown 是一种 HTML 文本标记语言,只要遵循它约定的语法格式,Markdown 的渲染器就能够把我们写的文章转换为标准的 HTML 文档,从而让我们的文章呈现更加丰富的格式,例如标题、列表、代码块等等 HTML 元素。

1.安装 Python Markdown

将 Markdown 格式的文本渲染成标准的 HTML 文档是一个复杂的工作,已经被封装成了一个 Python 第三方库。安装 Markdown即可使用

pip install -i https://pypi.douban.com/simple markdown

2.在 detail 视图中渲染 Markdown

将 Markdown 格式的文本渲染成 HTML 文本非常简单,只需调用这个库的 markdown 方法即可。我们书写的博客文章内容存在 Post 的 body 属性里,回到我们的详情页视图函数,对 post 的 body 的值做一下渲染,把 Markdown 文本转为 HTML 文本再传递给前端模板:

# blog/views.py 

import markdown 
from django.shortcuts import render, get_object_or_404 
from .models import Post

def detail(request, id):
    post = get_object_or_404(Post, id=id)
    # 记得在顶部引入 markdown 模块
    # extensions,它是对 Markdown 语法的拓展,这里我们使用了三个拓展
    # 1). extra 本身包含很多拓展,
    # 2). codehilite 是语法高亮拓展
    # 3). toc 则允许我们自动生成目录
    post.body = markdown.markdown(post.body,
                                  extensions=[
                                      'markdown.extensions.extra',
                                      'markdown.extensions.codehilite',
                                      'markdown.extensions.toc',
                                  ])

    return render(request, 'blog/detail.html', context={'post': post})

3.使用 safe 过滤器 解除Django 转义

发布的文章详情页没有看到预期的效果,而是类似于一堆乱码一样的 HTML 标签,这些标签本应该在浏览器显示它本身的格式,但是 Django 出于安全方面的考虑,任何的 HTML 代码在 Django 的模板中都会被转义(即显示原始的 HTML 代码,而不是经浏览器渲染后的格式)。为了解除转义,只需在模板标签使用 safe 过滤器即可,告诉 Django ,这段文本是安全的,你什么也不用做。
在模板中找到展示博客文章主体的 {{ post.body }} 部分,为其加上 safe 过滤器, {{ post.body|safe }} ,即可。
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第23张图片

第六步 代码高亮

我们在渲染时使用了 codehilite 拓展,但这只是实现代码高亮的第一步,还需要简单的几步才能达到我们的最终目的。

1.安装 Pygments

安装了一下 Pygments 什么也没做,但 Markdown 使用 Pygments 在后台为我们做了很多事。如果你打开博客详情页,找到一段代码段,在浏览器查看这段代码段的 HTML 源代码,可以发现 Pygments的工作原理是把代码切分成一个个单词,然后为这些单词添加 css 样式,不同的词应用不同的样式,这样就实现了代码颜色的区分,即高亮了语法。为此,还差最后一步,引入一个样式文件来给这些被添加了样式的单词定义颜色。

pip install -i https://pypi.douban.com/simple Pygments

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第24张图片

2.引入样式文件

在项目的 static\css\highlights\ 目录下应该能看到很多 .css 样式文件,这些文件是用来提供代码高亮样式的。选择一个你喜欢的样式文件,在 base.html 引入即可(别忘了使用 static 模板标签)。这里引入github.css 和 vim.css的样式,那么引入这个文件:

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第25张图片

3.发现代码依然没有高亮,依次检查以下步骤

确保在渲染文本时添加了 markdown.extensions.codehilite 拓展。
确保安装了 Pygments。
确保代码块的 Markdown 语法正确。
确保用于代码高亮的样式文件被正确地引入。

4.浏览器端测试

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第26张图片

第七步 页面侧边栏

博客侧边栏有四项内容:最新文章、归档、分类和标签云。这些内容相对比较固定,且在各个页面都会显示,如果像文章列表或者文章详情一样,从视图函数中获取然后传递给模板,则每个页面对应的视图
函数里都要写一段获取这些内容的代码,这会导致很多重复代码。更好的解决方案是直接在模板中获
取,为此,我们使用 Django 的一个新技术:自定义模板标签来完成任务。

1.内置的模板标签

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第27张图片

2.自定义模板标签

(1)模板标签目录结构

在我们的 blog 应用下创建一个 templatetags 包。包含 init.py 文件,之后在 templatetags\ 目录下创建一个 blog_tags.py 文件,这个文件存放自定义的模板标签代码。

新建一个包
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第28张图片

(2)最新文章模板标签

自定义模板标签代码写在 blog_tags.py 文件中。其实模板标签本质上就是一个 Python 函数,因此按照Python 函数的思路来编写模板标签的代码就可以了.

# blog/templatetags/blog_tags.py

from django import template
from ..models import Post

# 创建模板库对象
register = template.Library()

# 将函数 get_recent_posts添加到模板中
#这里我的理解: 之前是用户输入url,通过url.py文件寻找一个路由,在视图函数里,会调取数据库中Post类的内容。这里也相当于调取数据库中Post类的内容。
@register.simple_tag
def get_recent_posts(num=5):
	#这里的时间计算: 从元年到寻找创建的时间,从小到大,加上负号,就是从大到小,那么取前num个
    posts=Post.objects.all().order_by('-created_time')[:num]
    return posts

(3)归档模板标签

和最新文章模板标签一样,先写好函数,然后将函数注册为模板标签即可。


# 归档的模板标签
@register.simple_tag
def archives():
    # 
   dates = Post.objects.dates('created_time', 'month', order='DESC')
   return  dates


这里 dates 方法会返回一个列表,列表中的元素为每一篇文章(Post)的创建时间,且是 Python 的 date对象,精确到月份,降序排列。接受的三个参数值表明了这些含义,一个是 created_time , 即 Post 的创建时间, month 是精度, order=‘DESC’ 表明降序排列(即离当前越近的时间越排在前面)。例如我们写了 3 篇文章,分别发布于 2017 年 2 月 21 日、2017 年 3 月 25 日、2017 年 3 月 28日,那么 dates 函数将返回 2017 年 3 月 和 2017 年 2 月这样一个时间列表,且降序排列,从而帮助我们实现按月归档的目的。

(4)分类模板标签


@register.simple_tag
def get_categories():
   # 别忘了在顶部引入 Category 类
   return Category.objects.all()

(5)标签云模板标签


@register.simple_tag
def get_tags():
   return Tag.objects.all()

3.使用自定义的模板标签

打开 base.html,为了使用模板标签,我们首先需要在模板中导入存放这些模板标签的模块,这里是blog_tags.py 模块。当时我们为了使用 static 模板标签时曾经导入过 {% load staticfiles %},这次在 {% load staticfiles %} 下再导入 blog_tags:
在这里插入图片描述
当时在model.py中定义了这个函数
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第29张图片
然后找到最新文章、归档、分类、标签云列表处,把里面的列表修改一下:

这里必须写 {% get_recent_posts as recent_posts %} # 将get_recent_posts 重命名未recent_posts ,并把获取到的值付给recent_posts
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第30张图片
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第31张图片

4.测试

加了新的文件一定要重新runserver
成功显示了最新文章列表、归档、分类、标签云等信息。
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第32张图片
点击第一篇博客
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第33张图片

第八步 分类与归档完善跳转连接

侧边栏已经正确地显示了最新文章列表、归档、分类等信息。现在来完善归档和分类功能,当用户点击归档下的某个日期或者分类下的某个分类时,跳转到文章列表页面,显示该日期或者分类下的全部文章。点击右侧栏最新文章,跳转相关文章

1.配置url

#blog/urls.py

# /post/1/
urlpatterns = [
    url(r'^$', views.index, name='index'),
    # ^: 以什么开头, $是以什么结尾。 [0-9]指单个数字, +代表前面的字符出现1次或者多次。
    # [0-9]+: 1, 2, 2344, 78888,
    # (?P[0-9]+) 关键字匹配
    # /post/1/   ====> 1满足正则规则的, 将id=1
    url(r'^post/(?P[0-9]+)/$', views.detail, name='detail'),
    
    # 获取指定分类信息的路由
    url(r'^category/(?P[0-9]+)/$', views.category, name='category'),
    url(r'^tag/(?P[0-9]+)/$', views.tag, name='tag'),
    url(r'^archives/(?P[0-9]{4})/(?P[0-9]{1,2})/$', views.archives, name='archives')
]

2.编写视图函数:

使用了模型管理器(objects)的 filter 函数来过滤文章。由于是按照日期归档,因此这里根据文章发表的年和月来过滤。

# blog/views.py

def category(request, id):
    """根据分类的id显示该分类的所有博客信息"""
    # 记得在开始部分导入 Category 类
    cate = get_object_or_404(Category, id=id)
    post_list = Post.objects.filter(category=cate).order_by('-created_time')
    return render(request, 'blog/index.html', context={'posts': post_list})

def tag(request, id):
    """根据分类的id显示该分类的所有博客信息"""
    # 记得在开始部分导入 Category 类
    tag = get_object_or_404(Tag, id=id)
    post_list = Post.objects.filter(tags=tag).order_by('-created_time')
    return render(request, 'blog/index.html', context={'posts': post_list})


def archives(request, year, month):
    # created_time__year, 创建日期是一个date对象, 获取日期的年份yesr属性, 用双下划线
    post_list = Post.objects.filter(created_time__year=year,
                                    created_time__month=month
                                    ).order_by('-created_time')
    return render(request, 'blog/index.html', context={'posts': post_list})

3.修改相应的模板

在模板找到各列表部分的代码,修改超链接的 href 属性,让用户点击超链接后跳转到文章归档页面:
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第34张图片
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第35张图片
为什么要使用 {% url %} 模板标签呢?
我们把超链接的 href 属性设置为 /archives/{{ date.year }}/{{ date.month }}/ 同样可以达到目的跳转页面,但是这种写法是硬编码的。
虽然现在 archives 视图函数对应的 URL 模式是这种形式,但是如果哪天这个模式改变了呢?如果使用了硬编码的写法,那你需要把每一处 /archives/{{ date.year }}/{{ date.month }}/ 修改为新的模式。但如果使用了 {% url %} 模板标签,则不用做任何修改。
简单来说, 就是Web项目的路由地址变化, 不需要去前端页面进行修改链接地址。便于代码的维护。

4.测试

点击Django分类时,跳转
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第36张图片

第九步 统计各个分类下的文章数

1. annotate 方法

在我们的博客侧边栏有分类列表,显示博客已有的全部文章分类。现在想在分类名后显示该分类下有多少篇文章,该怎么做呢?最优雅的方式就是使用 Django 模型管理器的 annotate 方法。

#blog/templatetags/blog_tags.py 

from django.db.models.aggregates import Count 
from blog.models import Category

@register.simple_tag
def get_categories():
    # 记得在顶部引入 count 函数
    # Count 计算分类下的文章数,其接受的参数为需要计数的模型的名称
    return Category.objects.annotate(num_posts=Count('post')).filter(num_posts__gt=0)
  • Category.objects.annotate 方法和 Category.objects.all类似,返回数据库中全部Category 的记录,但它会做额外的事情: 统计每个Category 的文章数。
  • Count 方法,接收一个和 Categoty 相关联的模型参数名(这里是 Post ,通过 ForeignKey 关联的),统计 Category 记录的集合中每条记录下的与之关联的 Post 记录的行数,也就是文章数,最后把这个值保存到 num_posts 属性中。
  • filter 方法把 num_posts 的值小于 1 的分类过滤掉。因为 num_posts 的值小于 1 表示该分类下没有文章,没有文章的分类我们不希望它在页面中显示。

2.模板中引入

现在在 Category 列表中每一项都新增了一个 num_posts 属性记录该 Category 下的文章数量,我们就可以在模板中引用这个属性来显示分类下的文章数量了。
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第37张图片

第十步 统计文章阅读量

如何精确地记录一篇文章的阅读量是一个比较复杂的问题,不过对于我们的博客来说,没有必要记录的那么精确。因此我们使用一种简单但有效的方式来记录博客文章的阅读量:文章每被浏览一次,则其阅读量 +1,即所谓的文章页面 PV(Page View)数。虽然简单粗暴,但却高效实用。

1.增加新字段

# blog/models.py 

class Post(models.Model):

    # 新增 views 字段记录阅读量
    views = models.PositiveIntegerField(default=0)

2.增加模型方法

一旦用户访问了某篇文章,这时就应该将 views 的值 +1,这个过程最好由 Post 模型自己来完成,因此再给模型添加一个自定义的方法:

# blog/models.py 

class Post(models.Model):

    # 新增 views 字段记录阅读量
    views = models.PositiveIntegerField(default=0)

    def increase_views(self):
        self.views += 1
        self.save(update_fields=['views'])

3.迁移数据库

一旦更改了模型,就需要迁移数据库,以便让 Django 将更改反应到数据库中。

python manage.py makemigrations 
python manage.py migrate

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第38张图片

4.修改视图函数

# blog/views.py 

def detail(request, pk): 
	post = get_object_or_404(Post, pk=pk) 

	# 阅读量 +1 
	post.increase_views() 
	# ...........

5.在模板中显示阅读量

在模板中显示阅读量和显示其它字段一样,只需要使用模板变量即可。即模板适当的地方使用 {{post.views }} 模板变量。这里我们分别修改两个地方,分别是 index.html 和 detail.html。

index.html
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第39张图片
detail.html
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第40张图片

6.浏览器端测试

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第41张图片

第十一步 修改 首页、关于、博客、联系 的跳转链接

关于可以写自己的简历
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第42张图片
点击首页进入index
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第43张图片
点击联系后进入我的github
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第44张图片
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第45张图片

十二步 将代码提交到gitee


(base) F:\ziliao\python_kaifa\my_code\11_Django项目\BlogProject>git add *
(base) F:\ziliao\python_kaifa\my_code\11_Django项目\BlogProject>git commit -m "add category archives tag .."
(base) F:\ziliao\python_kaifa\my_code\11_Django项目\BlogProject>git push origin master
Username for 'https://gitee.com': dadadaliuliuliiu
Password for 'https://[email protected]':

十三步 部署

在部署项目前,编写README.md文件
并将项目环境所需的包导入requirements.txt文件

 F:\ziliao\python_kaifa\my_code\11_Django项目\BlogProject>pip freeze > requirements.txt

Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第46张图片
连接数据库前在__init__.py文件中设置
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第47张图片
部署和flask一样 端口换成5001和81端口
Django项目 ------支持Markdown语法和代码高亮的个人博客系统_第48张图片

你可能感兴趣的:(Django项目 ------支持Markdown语法和代码高亮的个人博客系统)