Django中按年月分类文章并实现可点击归档功能求助
解决Django文章按年月归档分组问题
当前站点4篇发布于2022年9月的文章在归档列表中重复显示,需实现按年月合并归档项、点击查看对应年月文章列表的功能,以下提供两种实现方式:
一、自定义实现方式
1. 修改视图归档数据查询逻辑
在blog/views.py的NewsDetailView中,修改get_context_data方法,按年月联合分组查询已发布文章:
from django.db.models import Count from django.db.models.functions import ExtractYear, ExtractMonth class NewsDetailView(TagMixin, DetailView): # 原有代码保持不变 def get_context_data(self, *, object_list=None, **kwargs): data = super().get_context_data(**kwargs) # 按年月分组,统计每个归档项的文章数量 data['news_archives'] = News.objects.filter(nw_status='published') \ .annotate(year=ExtractYear('nw_publish'), month=ExtractMonth('nw_publish')) \ .values('year', 'month') \ .annotate(total_articles=Count('id')) \ .order_by('-year', '-month') # 按时间倒序排列 return data
2. 添加按月归档视图
在blog/views.py中新增视图,用于展示指定年月的文章列表:
from django.views.generic.dates import MonthArchiveView class NewsMonthArchiveView(MonthArchiveView): model = News date_field = "nw_publish" year_format = '%Y' month_format = '%m' make_object_list = True # 返回对应年月的所有文章 allow_future = True context_object_name = 'newss' template_name = 'blog/news.html' # 复用现有新闻列表模板 queryset = News.objects.filter(nw_status='published').order_by('-nw_publish')
3. 配置归档URL
在blog/urls.py中添加按月归档的路由:
urlpatterns = [ # 原有URL保持不变 path('news/<int:year>/<int:month>/', NewsMonthArchiveView.as_view(), name="news_month_archive"), ]
4. 修改模板渲染归档列表
替换templates/news_details.html中的归档列表代码,显示合并后的年月项并生成可点击链接:
<ul class="sidebar__category-list list-unstyled"> {% for archive in news_archives %} <li> <a href="{% url 'blog:news_month_archive' archive.year archive.month %}"> <i class="fas fa-arrow-circle-right"></i> {{ archive.year }}年{{ archive.month }}月 ({{ archive.total_articles }}篇) </a> </li> {% empty %} <li>暂无归档内容</li> {% endfor %} </ul>
二、使用Django内置ArchiveView方式
1. 完善归档视图配置
在blog/views.py中保留NewsYearArchiveView,并添加NewsMonthArchiveView(同自定义方式中的视图代码),还可新增归档首页视图(可选):
from django.views.generic.dates import ArchiveIndexView class NewsArchiveIndexView(ArchiveIndexView): model = News date_field = "nw_publish" template_name = 'blog/news_archive_index.html' queryset = News.objects.filter(nw_status='published')
2. 在视图中注入归档日期列表
在需要显示侧边栏归档的视图(如NewsDetailView)中,添加自动分组的日期列表上下文:
class NewsDetailView(TagMixin, DetailView): # 原有代码保持不变 def get_context_data(self, *, object_list=None, **kwargs): data = super().get_context_data(**kwargs) # 获取所有有发布文章的年月列表 from django.views.generic.dates import _date_list queryset = News.objects.filter(nw_status='published') data['date_list'] = _date_list(queryset, 'nw_publish', 'month') return data
3. 修改模板渲染归档列表
使用Django自动生成的date_list渲染归档项:
<ul class="sidebar__category-list list-unstyled"> {% for date in date_list %} <li> <a href="{% url 'blog:news_month_archive' date.year date.month %}"> <i class="fas fa-arrow-circle-right"></i> {{ date.year }}年{{ date.month }}月 </a> </li> {% empty %} <li>暂无归档内容</li> {% endfor %} </ul>
4. 配置完整归档URL
在blog/urls.py中补充归档路由:
urlpatterns = [ # 原有URL保持不变 path('news/archive/', NewsArchiveIndexView.as_view(), name="news_archive_index"), path('news/<int:year>/', NewsYearArchiveView.as_view(), name="news_year_archive"), path('news/<int:year>/<int:month>/', NewsMonthArchiveView.as_view(), name="news_month_archive"), ]
额外注意事项
- 所有归档查询需过滤
nw_status='published',避免草稿文章显示在归档中 - 模板中URL名称需与
urls.py定义的name严格一致 - 若需在多个页面复用归档侧边栏,可将归档列表代码抽离为独立模板片段,通过
{% include %}引入
内容的提问来源于stack exchange,提问作者Sanji Vinsmoke
相关产品推荐
相关产品推荐

