15、上下篇博客和按月分类
我们打开一篇博文之后,如果我们想要看上一篇下一篇,有一个直接的链接可以点击,就会方便很多,那么自然而然就会产生这样的需求:有上一篇下一篇的按钮
1、上一篇和下一篇博客
- 对比当前博客,得到上一篇或下一篇
比如:
假如我们打开的是 id=3 的博客,它的上一篇就是 id=4 的博客,下一篇就是id=2的博客。既然我们是按照创建时间倒序排序的,那么能不能按照创建时间来进行。这里我们就可以用filter
,通过某些条件进行查询,得到 QuerySet,比如想找到上一篇博客,即日期比2018年1月27号大的所有博客,然后取查询结果里的最后一条;想找到下一篇博客,即日期比2018年1月27号小的所有博客,然后取查询结果里的第一条。
2、filter筛选条件
- 等于:直接筛选
- 其他常用查找类型:
- 大于:
__gt(greater than)
- 大于等于:
__gte
- 小于:
__lt(less than)
- 小于等于:
__lte
- 包含:
__contains(加 i 忽略大小写)
- 开头是:
__startswith
- 结尾是:
__endswith
- 其中之一:
__in
- 范围:
__range
- 大于:
修改views.py如下:
blog = get_object_or_404(Blog, pk=blog_pk)
context['previous_blog'] = Blog.objects.filter(created_time__gt=blog.created_time).last() # 找到比当前博客创建日期大的所有博客集合,last()取最后一条
context['next_blog'] = Blog.objects.filter(created_time__lt=blog.created_time).first() # 找到比当前博客创建日期小的所有博客集合,first()取第一条
context['blog'] = blog
修改blog_detail.html如下:
<div class="blog-more">
<p>上一篇:
{% if previous_blog %}
<a href="{% url 'blog_detail' previous_blog.pk %}">{{ previous_blog.title }}</a>
{% else %}
没有了
{% endif %}
</p>
<p>下一篇:
{% if next_blog %}
<a href="{% url 'blog_detail' next_blog.pk %}">{{ next_blog.title }}</a>
{% else %}
没有了
{% endif %}
</p>
</div>
修改blog.css如下:
演示其他filter筛选条件:
3、exclude 排除条件
- 用法和
filter
一样,都是得到查询(QuerySet) - 相当于
filter
条件取反 filter
等于=>不等于
4、条件中的双下划线
- 字段查询类型
- 外键拓展(以博客分类为例)
- 日期拓展(以月份分类为例)
- 支持链式查询:可以一直链接下去
除了按照博客类型分类,我们还能不能按照发表日期(年份月份)来进行分类呢?
修改blog\urls.py如下:
修改blog_list.html如下:
修改blog/views.py如下:
其中context['blog_dates'] = Blog.objects.dates('created_time', 'month', order='DESC')
,可以参考django官方文档:
修改全局变量mysite\static\base.css如下:
继续完善blog/views.py中的blogs_with_date方法 如下:
def blogs_with_date(request, year, month):
context = {}
blogs_all_list = Blog.objects.filter(created_time__year=year, created_time__month=month) # 获取所有博客
# 分页器
paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) # 每多少篇博客作为一页
page_num = request.GET.get('page', 1) # 获取页码参数(GET请求)
page_of_blogs = paginator.get_page(page_num) # 这里get_page方法,如果获取到的是其他字符而不是整数数字,会自动转化为1,使得它是处于有效的范围内
current_page_num = page_of_blogs.number # 获取当前页码
# 获取当前页码前后各2页的页码范围
page_range = list(range(max(current_page_num-2, 1), min(current_page_num+3, paginator.num_pages+1)))
# 先加上省略页码标记
if page_range[0] - 1 >= 2:
page_range.insert(0, '...')
if paginator.num_pages - page_range[-1] >= 2:
page_range.append('...')
# 然后加上首页和尾页
if page_range[0] != 1:
page_range.insert(0, 1)
if page_range[-1] != paginator.num_pages:
page_range.append(paginator.num_pages)
context = {}
context['blogs_with_date'] = '%s年%s月' % (year, month)
context['blogs'] = page_of_blogs.object_list
context['page_of_blogs'] = page_of_blogs # 返回具体的博客给前端模板页面
context['page_range'] = page_range
context['blog_types'] = BlogType.objects.all()
context['blog_dates'] = Blog.objects.dates('created_time', 'month', order='DESC') # 第一个参数是字段,用字符串;第二个参数是类型 月份;第三个参数是倒序
return render_to_response("blog/blogs_with_date.html", context)
创建blogs_with_date.html(类似于blogs_with_type.html)
<!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\blog\templates\blog\blogs_with_date.html -->
{% extends 'blog/blog_list.html' %}
{% block title %}
{{ blog_type.type_name }}
{% endblock %}
{% block blog_list_title %}
日期归档:{{ blogs_with_date }}
<a href="{% url 'blog_list' %}">查看全部博客</a>
{% endblock %}
刷新页面:
再回头看views.py中各个方法的代码,可以看到有很多重复的代码,我们进行完善一下,将各个方法的公共部分代码放到一个新建的方法中,然后其他方法调用这个公共方法即可:
# # C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\blog\views.py
from django.shortcuts import render_to_response, get_object_or_404 # render_to_response:用模板页面输出响应内容
from django.core.paginator import Paginator
from django.conf import settings
from .models import Blog, BlogType # 引入BlogType这个模型
def get_blog_list_common_data(request, blogs_all_list):
paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) # 每多少篇博客作为一页
page_num = request.GET.get('page', 1) # 获取页码参数(GET请求)。# 看有没有‘page’这个属性,如果没有,则默认给1
page_of_blogs = paginator.get_page(page_num) # 这里get_page方法,如果获取到的是其他字符而不是整数数字,会自动转化为1,使得它是处于有效的范围内
current_page_num = page_of_blogs.number # 获取当前页码
# 获取当前页码前后各2页的页码范围
page_range = list(range(max(current_page_num-2, 1), min(current_page_num+3, paginator.num_pages+1)))
# 先加上省略页码标记
if page_range[0] - 1 >= 2:
page_range.insert(0, '...')
if paginator.num_pages - page_range[-1] >= 2:
page_range.append('...')
# 然后加上首页和尾页
if page_range[0] != 1:
page_range.insert(0, 1)
if page_range[-1] != paginator.num_pages:
page_range.append(paginator.num_pages)
context = {}
context['blogs'] = page_of_blogs.object_list
context['page_of_blogs'] = page_of_blogs # 修改。返回具体的博客给前端模板页面
context['page_range'] = page_range
context['blog_types'] = BlogType.objects.all()
context['blog_dates'] = Blog.objects.dates('created_time', 'month', order='DESC')
return context
# 需要两个处理方法:1.访问博客列表;2.显示具体的blog页面
def blog_list(request):
blogs_all_list = Blog.objects.all() # 获取所有博客
context = get_blog_list_common_data(request, blogs_all_list)
return render_to_response("blog/blog_list.html", context)
# 处理分类博客的页面的方法——按照博客类型分类
def blogs_with_type(request, blog_type_pk):
blog_type = get_object_or_404(BlogType, pk=blog_type_pk)
blogs_all_list = Blog.objects.filter(blog_type=blog_type) # 筛选出该分类下博客
context = get_blog_list_common_data(request, blogs_all_list)
context['blog_type'] = blog_type # 该分类类型
return render_to_response("blog/blogs_with_type.html", context)
# 处理分类博客的页面的方法——按照创建日期分类
def blogs_with_date(request, year, month):
blogs_all_list = Blog.objects.filter(created_time__year=year, created_time__month=month) # 获取所有博客
context = get_blog_list_common_data(request, blogs_all_list)
context['blogs_with_date'] = '%s年%s月' % (year, month)
return render_to_response("blog/blogs_with_date.html", context)
# 具体的blog页面需要传一个参数进来,这个参数就是主键id(主键pk)
def blog_detail(request, blog_pk):
context = {}
blog = get_object_or_404(Blog, pk=blog_pk)
context['previous_blog'] = Blog.objects.filter(created_time__gt=blog.created_time).last() # 找到比当前博客创建日期大的所有博客集合,last()取最后一条
context['next_blog'] = Blog.objects.filter(created_time__lt=blog.created_time).first() # 找到比当前博客创建日期小的所有博客集合,first()取第一条
context['blog'] = blog
return render_to_response('blog/blog_detail.html', context)