[Django 30Days] Day13 Blog實作範例一上下篇文章切換與按月分類

SH Tseng
Leonard like a robot. Software, Data, Life Note
11 min readNov 25, 2020

D13 當點進文章內容頁以後,無法直接切換上下頁,只能返回上一頁以後再繼續,因此要做文章上下篇的切換並將類別增加可以按時間(月分類)。

上下篇文章切換

用以下測試資料來講解。

以id=4為例日期是20200524,下一篇是id=3日期20200523,
上一篇是id=5日期20200525,由於在models.py中是按照文章建立時間降序排列,或許可以用filter配文章建立時間做上下篇。下一篇的作法可以filter日期比0524小的資料,取第一筆資料。
上一篇的作法可以filter日期比0525大的資料,取最後一筆資料。
這種篩選的方法在Django中可以用filter與Field lookups進行條件查詢。

部分Field
myblog/views.py
PostDetailView
class PostDetailView(View):
template_name = 'myblog/post_detail.html'
def get(self, request, pk):
post = get_object_or_404(BlogPost, pk=pk)
context = {}
context['post'] = post
context['previous_post'] = PostBlog.objects.filter(created_at__gt=post.created_at).last()
context['next_post'] = PostBlog.objects.filter(created_at__lt = post.created_at).first()
return render(request, self.template_name, context)
templates/post_detail.html
在<p class="lead">{{ post.content }}</p>
<hr>之後加上下篇的HTML
<div>
<p>上一篇:
{% if previous_post %}
<a href="{% url 'post-detail' previous_post.pk %}"> {{
previous_post.title }} </a>
{% else %}
沒有上一篇
{% endif %}
</p>
<p>下一篇:
{% if next_post %}
<a href="{% url 'post-detail' next_post.pk %}"> {{
next_post.title }} </a>
{% else %}
沒有下一篇
{% endif %}
</p>
</div>
若previous_post存在則導向上一篇,沒有則顯示沒有上一篇。
若next_post存在則導向下一篇,沒有則顯示沒有下一篇。

日期分類

日期分類與上面的類別分類其實是大同小異的,不過我們要用一個queryset方法filter資料。

https://docs.djangoproject.com/en/3.1/ref/models/querysets/
dates(field, kind, order=”ASC”)
Returns a QuerySet that evaluates to a list of datetime.date objects representing all available dates of a particular kind within the contents of the QuerySet.

  1. "year" returns a list of all distinct year values for the field.
  2. "month" returns a list of all distinct year/month values for the field.
  3. "day" returns a list of all distinct year/month/day values for the field.
myblog/urls.py
新增日期分類的url 取名post-category-date
path('post/date/<int:yyyy>/<int:mm>',PostDateView.as_view(), name='post-category-date')
myblog/views.py
PostListView
新增日期篩選,年月,降序排列。
context['posts_date'] = BlogPost.objects.dates('created_at', 'month', order="DESC")
templates/post_list.html
在分類區塊,類別分類{% endfor %}之後新增
<div class="alert alert-secondary" role="alert">
<h4>日期分類</h4>
</div>
<ul style = "list-style-type: none;">
{% for post_date in posts_date %}
<a href="{% url 'post-category-date' post_date.year
post_date.month %}">
{{ post_date|date:'Y/m' }}</a>
{% endfor %}
</ul>

右邊欄日期分類出現。

日期分類內頁

View的方面也是大同小異,將categoy的view複製過來後進行修改。

myblog/views.py
class PostDateView(View):
template_name = 'myblog/post_category_date.html'
def get(self, request,yyyy, mm):
post_list = BlogPost.objects.filter(created_at__year=yyyy,
created_at__month=mm) #哪一年月的post
paginator = Paginator(post_list, 5) #每5篇文進行分頁
page_num = request.GET.get('page', 1) #get url 頁面參數
page_of_posts = paginator.get_page(page_num)
curr_page_num = page_of_posts.number #取現在頁碼
#取現在頁碼前後兩頁的範圍
page_range_display = list(range(max(curr_page_num -2,1),
curr_page_num)) + \
list(range(curr_page_num, min(curr_page_num + 2,
paginator.num_pages) + 1))#前頁碼省略記號與後頁碼省略記號

if page_range_display[0] - 1 >= 2:
page_range_display.insert(0, "...")
if paginator.num_pages - page_range_display[-1] >= 2:
page_range_display.append('...')
#第一頁與最後一頁
if page_range_display[0] != 1:
page_range_display.insert(0,1)
if page_range_display[-1] != paginator.num_pages:
page_range_display.append(paginator.num_pages)
context = {}
context['posts_with_date'] = f"{yyyy}/{mm}"
context['posts'] = page_of_posts.object_list
context['posts_list'] =post_list
context['page_of_posts'] = page_of_posts
context['page_range_display'] = page_range_display
context['category_list'] = BlogPostCategory.objects.all()
context['posts_date'] = BlogPost.objects.dates('created_at',
'month', order="DESC")
return render(request, self.template_name, context)
"""post_list = BlogPost.objects.filter 改為經由年月篩選資料
context['posts_with_date'] = f"{yyyy}/{mm}" 將年月往前端傳用來顯示標題
context['posts_list'] =post_list 這個月份的所有文章
context['posts_date'] = BlogPost.objects.dates('created_at',
'month', order="DESC") 共有那些月份
"""post_list.html
因為分類頁都可以延伸文章列表頁,因此將post_list.html 標頭統計幾篇文章的部分加上
{% block post_list_title %}{% endblock %}方便延伸。
<!--Alert class 並放大字體、利用hr標籤畫線分隔-->
<div class="col-md-8" style="margin-left:-8%">
<div class="alert alert-secondary" role="alert">
{% block post_list_title %}<h4>共有 {{ page_of_posts.paginator.count }} 篇文章</h4>{% endblock %}
</div>
post_category_date.html

{% extends "myblog/post_list.html" %}
{% block title %} 日期分類 : {{ post_by_categories.name }} {% endblock %}
{% block post_list_title%}
<h4>日期: {{ posts_with_date }} 共有 {{ posts_list|length }} 篇文章
</h4>
<a href="/myblog/post" style"font-size:14px>返回文章列表</a>
{% endblock %}
"""
因此我們只需要直接延伸post_list.html頁面,修改post_list_title的部分顯示by月份的文章數量。
"""

部落格系列部做到這想暫時落歇息一下,接下來幾天會安插幾篇製作小demo,後續再繼續用部落格範例測試Django的功能。

Reference:

django documentation

楊仕航的blog

--

--