Django个人博客搭建1-创建Django项目和第一个App
Django个人博客搭建2-编写文章Model模型,View视图
Django个人博客搭建3-创建superuser并向数据库中添加数据并改写视图
Django个人博客搭建4-配置使用 Bootstrap 4 改写模板文件
Django个人博客搭建5-编写文章详情页面并支持markdown语法
Django个人博客搭建6-对文章进行增删查改
Django个人博客搭建7-对用户登陆注册等需求的实现
Django个人博客搭建8-优化文章模块
Django个人博客搭建9-增加文章评论模块
1.文章分页
利用Django内置的分页模块:Paginator类(:Paginator官网例子),因为是对文章分页,因此需要修改article/views.py中article_list视图:
from django.core.paginator import Paginator# 文章列表函数def article_list(request):# 取出所有博客文章article_list = ArticlePost.objects.all()# 每页显示一篇文章paginator = Paginator(article_list, 1)# 获取url中的页码page = request.GET.get('page')# 将导航对象相应的页码内容返回给articlesarticles = paginator.get_page(page)# 需要传递给模板对象context = {'articles': articles}# render函数载入模板,并返回context对象return render(request, 'article/list.html', context)# article/list.html:模板位置context:传入模板的对象
接下来修改templates/article/list.html加入分页内容
...<div class="pagination row"><div class="m-auto"><span class="step-links"><!-- 如果不是第一页,则显示上翻按钮 -->{% if articles.has_previous %}<a href="?page=1" class="btn btn-success">« 1</a><span>...</span><a href="?page={{ articles.previous_page_number }}"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 }}"class="btn btn-secondary">{{ articles.next_page_number }}</a><span>...</span><a href="?page={{ articles.paginator.num_pages }}"class="btn btn-success">{{ articles.paginator.num_pages }} »</a>{% endif %}</span></div></div>
最后查看效果:
分页功能完成
2.文章浏览量
首先修改文章的模型article/models.py
# 博客文章数据模型class ArticlePost(models.Model):...updated = models.DateTimeField(auto_now=True)total_views = models.PositiveIntegerField(default=0)...
PositiveIntegerField是用于存储正整数的字段
接着生成迁移
python manage.py makemigrations
F:\Desktop\myblog>python manage.py makemigrationsSystem check identified some issues:WARNINGS:article.ArticlePost.created: (fields.W161) Fixed default value provided.HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. If you want to have the current date as default, use `django.utils.timezone.now`Migrations for 'article':article\migrations\0003_auto_0210_1956.py- Add field total_views to articlepost- Alter field created on articlepostMigrations for 'userprofile':userprofile\migrations\0002_auto_0210_1956.py- Alter field avatar on profile
执行迁移:
F:\Desktop\myblog>python manage.py migrateSystem check identified some issues:WARNINGS:article.ArticlePost.created: (fields.W161) Fixed default value provided.HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. If you want to have the current date as default, use `django.utils.timezone.now`Operations to perform:Apply all migrations: admin, article, auth, contenttypes, sessions, userprofileRunning migrations:Applying article.0003_auto_0210_1956... OKApplying userprofile.0002_auto_0210_1956... OKF:\Desktop\myblog>
我们一般需要在文章列表和文章详情中显示各个文章的浏览量,因此先修改article/list.html
...<div class="card-footer"><a href="{% url 'article:article_detail' article.id %}" class="btn btn-primary">阅读本文</a><span><small class="col align-self-end" style="color: gray;">浏览量:{{ article.total_views }}</small></span>...
接着修改详情模板article/detail.html:
<!-- extends表明此页面继承自 base.html 文件 -->{% extends "base.html" %}{% load staticfiles %}<!-- 写入 base.html 中定义的 title -->{% block title %}文章详情{% endblock title %}<!-- 写入 base.html 中定义的 content -->{% block content %}<!-- 文章详情 --><div class="container">...{% if user == article.author %}.<a href="#" onclick="confirm_delete()">删除文章</a>.<a href="{% url "article:article_update" article.id %}">编辑文章</a>{% endif %}</div><div>浏览量:{{ article.total_views }}</div><div class="col-12"><p>{{ article.body|safe }}</p>...{% endblock content %}
首先修改得就是检查登陆用户是否为文章作者本人,如果是本人才会显示删除和编辑文章,接着在下面增加显示浏览量
重启服务器:
可以看见文章列表可以显示文章浏览量了,点击阅读本文:
前面修改了修改删除文章得权限,因此用户没有登陆时时没有这两个选项的,我们点击登陆
登陆后就显示了,但是由于没有对浏览量的进行逻辑处理,就是文章的浏览量总是初始给定的0,因此修改article/views.py中article_detail使其点击一次文章详情total_views就+1:
def article_detail(request, id):...article.total_views += 1article.save(update_fields=['total_views'])...
update_fields=[]指定了数据库只更新total_views字段,优化执行效率。
我们重新刷新一下详情页面:
发现文章的浏览量已经自动增加了
这样文章浏览量功能就已经完成了
3.根据浏览量排序最热文章:
重写article/views.py:article_list():
# 文章列表函数def article_list(request):# 根据GET请求中查询条件# 返回不同排序的对象数组if request.GET.get('order') == 'total_views':article_list = ArticlePost.objects.all().order_by('-total_views')order = 'total_views'else:article_list = ArticlePost.objects.all()order = 'normal'paginator = Paginator(article_list, 3)page = request.GET.get('page')articles = paginator.get_page(page)# 修改此行context = {'articles': articles, 'order': order}return render(request, 'article/list.html', context)
'-total_views’为反序,即文章浏览量高的在前面
接下来修改templates/article/list.html
...{% block content %}<!-- 定义放置文章标题的div容器 --><div class="container"><nav aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="{% url 'article:article_list' %}">最新</a></li><li class="breadcrumb-item"><a href="{% url 'article:article_list' %}?order=total_views">最热</a></li></ol></nav><div class="row mt-2">{% for article in articles %}<!-- 文章内容 -->...
重启服务器点击最热查看效果:
可以看见文章排序是按照文章浏览量排序的了
这样最热文章功能就完成了
4.搜索文章功能
Q对象
Model.objects.all()能够返回表中的所有对象。
对应的,Model.objects.filter(**kwargs)可以返回与给定参数匹配的部分对象。
还有Model.objects.exclude(**kwargs)返回与给定参数不匹配的对象
如果想对多个参数进行查询怎么办?比如同时查询文章标题和正文内容。这时候就需要Q对象。
首先修改article/views.py
# 文章列表函数def article_list(request):search = request.GET.get('search')order = request.GET.get('order')# 用户搜索逻辑,请求中有search,则走次逻辑if search:if order == 'total_views':# 用q对象进行联合搜索article_list = ArticlePost.objects.filter(Q(title__contains=search)| # icontains不区分分大小写,contains区分大小写Q(body__icontains=search)).order_by('-total_views')else:article_list = ArticlePost.objects.filter(Q(title__contains=search) |Q(body__icontains=search))# 根据GET请求中查询条件# 返回不同排序的对象数组else:search = ''if order == 'total_views':article_list = ArticlePost.objects.all().order_by('-total_views')else:article_list = ArticlePost.objects.all()paginator = Paginator(article_list, 3)page = request.GET.get('page')articles = paginator.get_page(page)# 修改此行context = {'articles': articles, 'order': order, 'search': search}return render(request, 'article/list.html', context)
接着修改模板:article/list.html
<nav aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="{% url 'article:article_list' %}">最新</a></li><li class="breadcrumb-item"><a href="{% url 'article:article_list' %}?order=total_views">最热</a></li></ol></nav><div class="row"><div class="col-auto mr-auto"><form class="form-inline"><label class="sr-only">content</label><input type="text"class="form-control"name="search"placeholder="搜索文章..."required></form></div></div>{# 搜索提示语 #}{% if search %}<h4><span style="color: red">{{ search }}</span>的搜索内容如下</h4><hr>{% else %}<h4>暂无<span style="color: red">{{ search }}</span> </h4>有关的文章<hr>{% endif %}<div class="row mt-2">{% for article in articles %}<!-- 文章内容 --><div class="col-4 mb-4"><!-- 卡片容器 --><div class="card h-100"><!-- 标题 --><h4 class="card-header">{{ article.title }}</h4><!-- 摘要 --><div class="card-body"><p class="card-text">{{ article.body|slice:'100' }}...</p></div><!-- 注脚 --><div class="card-footer"><a href="{% url 'article:article_detail' article.id %}" class="btn btn-primary">阅读本文</a><span><small class="col align-self-end" style="color: gray;">浏览量:{{ article.total_views }}</small></span></div></div></div>{% endfor %}</div></div><div class="pagination row"><div class="m-auto"><span class="step-links"><!-- 如果不是第一页,则显示上翻按钮 -->{% if articles.has_previous %}<a href="?page=1&order={{ order }}&search={{ search }}" class="btn btn-success">« 1</a><span>...</span><a href="?page={{ articles.previous_page_number }}&order={{ order }}&search={{ search }}"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 }}&search={{ search }}"class="btn btn-secondary">{{ articles.next_page_number }}</a><span>...</span><a href="?page={{ articles.paginator.num_pages }}&order={{ order }}&search={{ search }}"class="btn btn-success">{{ articles.paginator.num_pages }} »</a>{% endif %}</span></div></div>
面包屑组件、页码组件都改动了href:增加了search参数
新增搜索栏,以GET请求提交search参数;required属性阻止用户提交空白文本
新增搜索提示语。好的UI必须让用户了解当前的状态
我们重启服务器打开文章列表页面
搜索java
这样文章的搜索功能就完成了
5.渲染Markdown目录
首先修改article/views.py:
# 文章详情def article_detail(request, id):...article.body = markdown.markdown(article.body,extensions=[# 包含 缩写、表格等常用扩展'markdown.extensions.extra',# 语法高亮扩展'markdown.extensions.codehilite',# 目录扩展'markdown.extensions.toc',])...
添加了一行代码,接着我们在之前的文章里添加几个级别的标题
其实就是插入不同级别的标题,然后在文章任何地方插入**[TOC]**即可自动生成目录
点击完成后观察效果:
如果我们想实现将目录插入到页面任何一个位置就徐娅萍修改Markdown的渲染方法:
# 文章详情def article_detail(request, id):article = ArticlePost.objects.get(id=id)article.total_views += 1article.save(update_fields=['total_views'])md = markdown.Markdown(extensions=[# 包含 缩写、表格等常用扩展'markdown.extensions.extra',# 语法高亮扩展'markdown.extensions.codehilite',# 目录扩展'markdown.extensions.toc',])article.body = md.convert(article.body)context = {'article': article, 'toc': md.toc}# 载入模板,并返回context对象preturn render(request, 'article/detail.html', context)
为了能将toc单独提取出来,我们先将Markdown类赋值给一个临时变量md,然后用convert()方法将正文渲染为html页面。通过md.toc将目录传递给模板。
修改article/detail.html
...<!-- 文章详情 --><div class="container"><div class="row"><div class="col-9"><h1 class="col-12 mt-4">{{ article.title }}</h1><div class="col-12 alert alert-success">作者: {{ article.author }}{% if user == article.author %}.<a href="#" onclick="confirm_delete()">删除文章</a>.<a href="{% url "article:article_update" article.id %}">编辑文章</a>{% endif %}</div><div>浏览量:{{ article.total_views }}</div><div class="col-12"><p>{{ article.body|safe }}</p></div></div>{# 目录 #}<div class="col-3 mt-4"><h4><strong>目录</strong><hr><div>{{ toc|safe }}</div></h4></div></div></div><script>//删除文章的函数function confirm_delete() {...
将原来的内容装进col-9的容器中,将右侧col-3的空间留给目录,toc需要|safe标签才能正确渲染
我们重新刷新页面:
发现右边已经正确显示目录了
Django个人博客搭建1-创建Django项目和第一个App
Django个人博客搭建2-编写文章Model模型,View视图
Django个人博客搭建3-创建superuser并向数据库中添加数据并改写视图
Django个人博客搭建4-配置使用 Bootstrap 4 改写模板文件
Django个人博客搭建5-编写文章详情页面并支持markdown语法
Django个人博客搭建6-对文章进行增删查改
Django个人博客搭建7-对用户登陆注册等需求的实现
Django个人博客搭建8-优化文章模块
Django个人博客搭建9-增加文章评论模块