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

如何在Wagtail中实现带URL参数的日历多路由页面?

在Wagtail中集成Django日历功能(支持月份切换与单日视图)

核心实现方案:基于RoutablePageMixin扩展Wagtail页面

你已经使用了RoutablePageMixin,只需通过装饰器定义三个路由规则,并在处理函数中统一处理日期参数即可实现需求。以下是完整的模型代码:

from django.utils import timezone
from django.shortcuts import redirect, render
from wagtail.contrib.routable_page.models import RoutablePageMixin, route

class SchedulePage(PostPageExtras, RoutablePageMixin, Page):
    content_panels = Page.content_panels

    def get_base_calendar_context(self, year=None, month=None, day=None):
        """统一处理日期参数,生成日历或单日视图的上下文"""
        now = timezone.now()
        # 缺失参数时使用当前日期
        the_year = year or now.year
        the_month = month or now.month
        the_day = day

        context = {
            'current_year': the_year,
            'current_month': the_month,
        }

        if the_day is not None:
            # 单日视图逻辑:替换为你原Django中的单日日程获取代码
            context['day_schedule'] = self.get_day_schedule(the_year, the_month, the_day)
            context['view_type'] = 'day'
        else:
            # 月历视图逻辑:调用原日历生成方法
            context['schedule'] = ScheduleCalendar().formatmonth(the_year, the_month, withyear=True)
            context['view_type'] = 'month'

        # 生成前后月份切换的URL
        prev_month = timezone.datetime(the_year, the_month, 1) - timezone.timedelta(days=1)
        next_month = timezone.datetime(the_year, the_month, 1) + timezone.timedelta(days=32)
        context['prev_month_url'] = self.reverse_subpage('month-view', args=[prev_month.year, prev_month.month])
        context['next_month_url'] = self.reverse_subpage('month-view', args=[next_month.year, next_month.month])

        return context

    def get_day_schedule(self, year, month, day):
        """获取指定日期的日程数据,替换为你的业务逻辑"""
        from yourapp.models import YourDayScheduleModel
        return YourDayScheduleModel.objects.filter(date=timezone.date(year, month, day))

    # 路由1:默认视图(无参数,显示当月日历)
    @route(r'^$')
    def default_view(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        context.update(self.get_base_calendar_context())
        return render(request, self.template, context)

    # 路由2:年月视图(显示指定月份日历)
    @route(r'^(?P<year>\d+)/(?P<month>\d+)/$', name='month-view')
    def month_view(self, request, year, month, *args, **kwargs):
        # 参数合法性校验
        try:
            year = int(year)
            month = int(month)
        except ValueError:
            return redirect(self.url)

        context = super().get_context(request, *args, **kwargs)
        context.update(self.get_base_calendar_context(year=year, month=month))
        return render(request, self.template, context)

    # 路由3:单日视图(显示指定日期详情)
    @route(r'^(?P<year>\d+)/(?P<month>\d+)/(?P<day>\d+)/$', name='day-view')
    def day_view(self, request, year, month, day, *args, **kwargs):
        # 参数合法性校验
        try:
            year = int(year)
            month = int(month)
            day = int(day)
            # 验证日期有效性
            timezone.date(year, month, day)
        except ValueError:
            return redirect(self.url)

        context = super().get_context(request, *args, **kwargs)
        context.update(self.get_base_calendar_context(year=year, month=month, day=day))
        return render(request, self.template, context)

模板适配

在你的SchedulePage模板中,根据view_type变量切换显示内容,并添加月份切换链接:

{% extends "your_wagtail_base_template.html" %}

{% block content %}
    {% if view_type == 'month' %}
        <h1>{{ current_year }}年{{ current_month }}月日程</h1>
        <!-- 月份切换按钮 -->
        <a href="{{ prev_month_url }}" class="btn">上一月</a>
        <a href="{{ next_month_url }}" class="btn">下一月</a>
        <!-- 渲染日历(注意用safe标签解析HTML) -->
        {{ schedule|safe }}
    {% elif view_type == 'day' %}
        <h1>{{ current_year }}年{{ current_month }}月{{ day }}日详情</h1>
        <a href="{% pageurl self %}" class="btn">返回月历</a>
        <!-- 渲染单日日程列表 -->
        {% for item in day_schedule %}
            <div class="schedule-item">
                <h3>{{ item.title }}</h3>
                <p>{{ item.time }} | {{ item.location }}</p>
            </div>
        {% empty %}
            <p>当日暂无日程安排</p>
        {% endfor %}
    {% endif %}
{% endblock %}

替代方案:在普通Django视图中加载Wagtail模板与导航

如果你更倾向于保留原Django视图的结构,可通过以下方式在普通视图中集成Wagtail的模板和导航:

1. 编写Django视图

from django.utils import timezone
from django.shortcuts import render, get_object_or_404
from wagtail.models import Site, Page
from yourapp.models import YourDayScheduleModel, ScheduleCalendar, BlogIndexPage

def schedule_calendar_view(request, year=None, month=None, day=None):
    # 获取当前Wagtail站点与根页面
    site = Site.find_for_request(request)
    root_page = site.root_page

    # 获取博客首页(用于继承Wagtail的导航与模板上下文)
    blog_index = get_object_or_404(BlogIndexPage, url_path__startswith=root_page.url_path)

    # 处理日期参数
    now = timezone.now()
    the_year = year or now.year
    the_month = month or now.month
    the_day = day

    context = {
        # Wagtail模板必需的上下文变量
        'site': site,
        'root_page': root_page,
        'page': blog_index,  # 用博客首页作为当前页,保证导航正常
        # 日历业务上下文
        'current_year': the_year,
        'current_month': the_month,
    }

    # 切换视图逻辑
    if the_day:
        context['day_schedule'] = YourDayScheduleModel.objects.filter(date=timezone.date(the_year, the_month, the_day))
        context['view_type'] = 'day'
    else:
        context['schedule'] = ScheduleCalendar().formatmonth(the_year, the_month, withyear=True)
        context['view_type'] = 'month'

    # 渲染Wagtail模板
    return render(request, 'yourapp/schedule_template.html', context)

2. 配置Django URL规则

在项目根目录的urls.py中添加路由:

from django.urls import path, re_path
from yourapp.views import schedule_calendar_view

urlpatterns = [
    # 保持你原有的URL模式
    path('schedule/', schedule_calendar_view, name='control-schedule-calendar'),
    re_path(r'^schedule/(?P<year>\d+)/(?P<month>\d+)/$', schedule_calendar_view, name='control-schedule-monthview'),
    re_path(r'^schedule/(?P<year>\d+)/(?P<month>\d+)/(?P<day>\d+)/$', schedule_calendar_view, name='control-schedule-dayview'),
]

3. 模板复用

模板结构与之前Wagtail页面的模板完全一致,直接继承你的Wagtail基础模板即可。

内容的提问来源于stack exchange,提问作者typonaut

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:57:32