目录
浏览量或者说文章热度是评估一篇博文质量的重要指数。一般的博客网站都具备统计以及按照浏览量排序的功能。
本文我们来实现博文浏览的统计,同时增加按照热度和时间排序的功能。
统计文章浏览量
修改模型
要实现浏览量功能,我们首先需要增加一个浏览量字段。
因此修改文章的模型:
# 博客文章数据模型
class Article(models.Model):
# 文章id,主键
id = models.AutoField(primary_key=True)
# 文章作者。修改为User的外键,参数 on_delete 用于指定数据删除的方式
author = models.ForeignKey(User, on_delete=models.CASCADE)
# 文章标题,models.CharField 为字符串字段,用于保存较短的字符串,比如标题
title = models.CharField('标题',max_length=100)
# 文章正文,保存大量文本使用 TextField
body = models.TextField('文章正文')
# 文章创建时间,参数 default=timezone.now 指定其在创建数据时将默认写入当前的时间
created = models.DateTimeField(default=timezone.now)
#增加浏览量字段
total_views = models.PositiveIntegerField(default=0)
# 文章更新时间,参数 auto_now=True 指定每次数据更新时自动写入当前时间
updated = models.DateTimeField(auto_now=True)
# 获取文章地址
def get_absolute_url(self):
return reverse('detail', args=[self.id])
PositiveIntegerField
是用于存储正整数的字段default=0
设定初始值从0开始
迁移下数据
python manage.py makemigrations
python manage.py migrate
修改视图
我们需要实现的是每当用户访问详情页面时,浏览量就加1。
因此修改article_detail()
如下:
# 文章详情
def article_detail(request,id):
# 取出相应的文章
article = Article.objects.get(id=id)
# 浏览量 +1
article.total_views += 1
article.save(update_fields=['total_views'])
# 取出文章评论
comments = Comment.objects.filter(article=id)
# 需要传递给模板的对象
context = {'article': article, 'comments': comments}
# 载入模板,并返回context对象
return render(request, 'article/detail.html', context)
update_fields=[]
指定了数据库只更新total_views
字段,优化执行效率。
修改列表模板
首先我们在列表的每个文章卡片上都加上一个阅读量的显示。
这里我们为了美观,我们加上一个阅读量的图标。
使用图标我们需要引入图标库,这里我们通过在线形式引入。
在templates/base.html
中增加如下代码:
<!-- 载入静态文件-->
{% load static %}
<!DOCTYPE html>
<!-- 网站主语言 -->
<html lang="zh-cn">
<head>
<!-- 网站采用的字符编码 -->
<meta charset="utf-8">
<!-- 预留网站标题的位置 -->
<title>{% block title %}{% endblock %}</title>
<!-- 引入bootstrap的css文件 -->
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
<!-- 引入图标库 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
</head>
然后在templates/article/list.html
中增加代码如下:
...
<div class="card-body">
<h4 class="card-title">{
{ article.title }}</h4>
<br>
<p class="card-text">{
{ article.body|slice:'100' }}...</p>
<a href="{% url 'detail' article.id %}" class="card-link">阅读本文</a>
<!-- 这里增加阅读量和图标 -->
<small class="col align-self-end" style="color: gray;">
<span class="bi bi-eye">
{
{ article.total_views }}
</span>
</small>
</div>
实现效果如下:
修改详情模板
类似的,我们在详情页面标题后面也增加图标和阅读量。
<div class="col-12 alert alert-primary">
<div class="col-12">
<a>作者:{
{ article.author }}</a>
 
<a>{
{ article.created|date:'Y-m-d H:i:s' }}</a>
 
<!-- 只有作者可以修改文章 -->
{% if user == article.author %}
<a href="#" data-bs-toggle="modal" data-bs-target="#myModal">删除文章</a>
<!-- 新增一个隐藏的表单 -->
<form
style="display:none;"
id="safe_delete"
action="{% url "delete" article.id %}"
method="POST"
>
{% csrf_token %}
<button type="submit">发送</button>
</form>
 
<a href="{% url "update" article.id %}">编辑文章</a>
{% endif %}
<!-- 增加阅读量和图标 -->
<small class="col align-self-end" style="color: gray;">
<span class="bi bi-eye">
{
{ article.total_views }}
</span>
</small>
</div>
</div>
以上代码我们在编辑文章后面增加了阅读量和图标,效果如下:
热度和时间排序
增加了浏览量字段后,我们继续实现排序功能。
修改视图
我们的排序功能主要是在列表页面,所以我们重新编写下article_list
视图:
def article_list(request):
# 根据GET请求中查询条件
# 返回不同排序的对象数组
if request.GET.get('order') == 'total_views':
article_list = Article.objects.all().order_by('-total_views')
order = 'total_views'
else:
article_list = Article.objects.all().order_by('created')
order = 'created'
paginator = Paginator(article_list, 2)
page = request.GET.get('page')
articles = paginator.get_page(page)
# 修改此行
context = { 'articles': articles, 'order': order }
return render(request, 'article/list.html', context)
视图函数关键代码解释如下:
- Get请求中,我们增加一个传递参数
order
,视图里面根据请求的参数不同对取出的文章对象按不同的字段进行排序。 - 这里我们只有两个排序选项,按浏览量和按创建日期,默认是按创建日期。
order_by('-total_views')
,order_by()
是排序方法,这里我们通过在整形字段前面加上负号,代表我们根据字段逆序排序(只有带符号字段可以如此操作)。context = { 'articles': articles, 'order': order }
,这里我们传递参数的时候将order
也一起传了,因为我们会有分页的动作,分页的时候不需要重新点击排序按钮了,需要指定当前的排序方法。
修改模板
接着修改列表模板,需要修改两个地方:
第一处我们在列表最上方增加两个排序选项,这里我们使用了Bootstrap
的面包屑导航组件
<!-- 写入 base.html 中定义的 content -->
{% block content %}
<!-- 定义放置文章标题的div容器 -->
<br>
<div class="container">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{% url 'list' %}">
最新
</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'list' %}?order=total_views">
最热
</a>
</li>
</ol>
</nav>
效果如下:
接着我们把分页的跳转链接也增加上order
参数:
<div class="pagination row">
<div class="m-auto">
<span class="step-links">
<!-- 如果不是第一页,则显示上翻按钮 -->
{% if articles.has_previous %}
<a href="?page=1&order={
{ order }}" class="btn btn-success">
« 1
</a>
<span>...</span>
<a href="?page={
{ articles.previous_page_number }}&order={
{ order }}"
class="btn btn-secondary"
>
{
{ articles.previous_page_number }}
</a>
{% endif %}
<!-- 当前页面 -->
<span class="current btn btn-danger btn-lg">
{
{ articles.number }}
</span>
<!-- 如果不是最末页,则显示下翻按钮 -->
{% if articles.has_next %}
<a href="?page={
{ articles.next_page_number }}&order={
{ order }}"
class="btn btn-secondary">{
{ articles.next_page_number }}</a>
<span>...</span>
<a href="?page={
{ articles.paginator.num_pages }}&order={
{ order }}"
class="btn btn-success">{
{ articles.paginator.num_pages }} »</a>
{% endif %}
</span>
</div>
</div>
结语
本篇我们增加了统计浏览量的功能,同时在此基础上,增加了博文列表排序的功能,可以根据最新或者最热来对文文章进行排序。
另外,我们引入了眼睛图标,来生动的展示阅读量效果。
下篇我们将实现博客网站的最后一个核心功能:搜索。