You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:13:15