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

跟随Wagtail教程添加标签时遭遇404页面未找到问题

问题:Wagtail博客点击标签出现404错误

按照Wagtail官方教程为快速入门博客添加标签后,点击添加的“foood”标签时出现Page not found (404)错误,请求路径/tags/?tag=foood无法匹配到对应页面。以下是相关代码:


相关代码

blog/models.py 中的 BlogTagIndexPage 类

# Add BlogTagIndexPage
class BlogTagIndexPage(Page):

    def get_context(self, request):
        # Filter by tag
        tag = request.GET.get('tag')
        blogpages = BlogPage.objects.filter(tags__name=tag)

        # Update template context
        context = super().get_context(request)
        context['blogpages'] = blogpages
        return context

blog/templates/blog/blog_tag_index_page.html 模板

{% extends "base.html" %}
{% load wagtailcore_tags %}

{% block content %}
    {% if request.GET.tag %}
        <h4>Showing pages tagged "{{ request.GET.tag }}"</h4>
    {% endif %}
        
    {% for blogpage in blogpages %}
          <p>
              <strong><a href="{% pageurl blogpage %}">{{ blogpage.title }}</a></strong><br />
              <small>Revised: {{ blogpage.latest_revision_created_at }}</small><br />
          </p> 
    {% empty %}
        No pages found with that tag.
    {% endfor %}
{% endblock %}

完整的 models.py 代码

from django.db import models
from django import forms

from modelcluster.fields import ParentalKey, ParentalManyToManyField
# add tags to allow users to view tagged content
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase


# add wagtail classes and methods
from wagtail.models import Page, Orderable
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel
from wagtail.search import index

# add snippets
from wagtail.snippets.models import register_snippet

# Add BlogTagIndexPage
class BlogTagIndexPage(Page):
    def get_context(self, request):
        # Filter by tag
        tag = request.GET.get('tag')
        blogpages = BlogPage.objects.filter(tags__name=tag)

        # Update template context
        context = super().get_context(request)
        context['blogpages'] = blogpages
        return context

class BlogIndexPage(Page):
    intro = RichTextField(blank=True)

    content_panels = Page.content_panels + [
        FieldPanel('intro')
    ]

    # add the get_context method:
    def get_context(self, request):
        # Update context to include only published posts, ordered by reverse-chron
        context = super().get_context(request)
        blogpages = self.get_children().live().order_by('-first_published_at')
        context['blogpages'] = blogpages
        return context


class BlogPageTag(TaggedItemBase):
    content_object = ParentalKey(
        'BlogPage',
        related_name='tagged_items',
        on_delete=models.CASCADE
    )

class BlogPage(Page):
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)

    # the main_image method:
    def main_image(self):
        gallery_item = self.gallery_images.first()
        if gallery_item:
            return gallery_item.image
        else:
            return None

    search_fields = Page.search_fields + [
        index.SearchField('intro'),
        index.SearchField('body'),
    ]

    # Add authors:
    authors = ParentalManyToManyField('blog.Author', blank=True)

    # Add tags:
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)

    content_panels = Page.content_panels + [
        # Add MultiFieldPanel including date panel, authors panel
        MultiFieldPanel([
            FieldPanel('date'),
            FieldPanel('authors', widget=forms.CheckboxSelectMultiple),
            # Add field for tags:
            FieldPanel('tags'),
        ], heading="Blog information"),

        FieldPanel('intro'),
        FieldPanel('body'),
        InlinePanel('gallery_images', label="Gallery images"),
    ]

class BlogPageGalleryImage(Orderable):
    page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='gallery_images')
    image = models.ForeignKey(
        'wagtailimages.Image', on_delete=models.CASCADE, related_name='+'
    )
    caption = models.CharField(blank=True, max_length=250)

    panels = [
        FieldPanel('image'),
        FieldPanel('caption'),
    ]

@register_snippet
class Author(models.Model):
    name = models.CharField(max_length=255)
    author_image = models.ForeignKey(
        'wagtailimages.Image', null=True, blank=True,
        on_delete=models.SET_NULL, related_name='+'
    )

    panels = [
        FieldPanel('name'),
        FieldPanel('author_image'),
    ]

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = 'Authors'

blog_page.html 模板

{% extends "base.html" %}

{% load wagtailcore_tags wagtailimages_tags %}

{% block body_class %}template-blogpage{% endblock %}

{% block content %}
    <h1>{{ page.title }}</h1>
    <p class="meta">{{ page.date }}</p>

    <!-- Add authors multi-field panel to blog page template: -->
    {% with authors=page.authors.all %}
        {% if authors %}
            <h3>Posted by:</h3>
            <ul>
                {% for author in authors %}
                    <li style="display: inline">
                        {% image author.author_image fill-40x60 style="vertical-align: middle" %}
                        {{ author.name }}
                    </li>
                {% endfor %}
            </ul>
        {% endif %}
    {% endwith %}

    <div class="intro">{{ page.intro }}</div>

    {{ page.body|richtext }}

    <!-- image gallery -->
    {% for item in page.gallery_images.all %}
        <div style="float: inline-start; margin: 10px">
            {% image item.image fill-320x240 %}
            <p>{{ item.caption }}</p>
        </div>
    {% endfor %}

    <p><a href="{{ page.get_parent.url }}">Return to blog</a></p>

    <!-- Add this: -->
    {% with tags=page.tags.all %}
        {% if tags %}
            <div class="tags">
                <h3>Tags</h3>
                {% for tag in tags %}
                    <a href="{% slugurl 'tags' %}?tag={{ tag }}"><button type="button">{{ tag }}</button></a>
                {% endfor %}
            </div>
        {% endif %}
    {% endwith %}
{% endblock %}

原因与解决方案

你遗漏了两个核心步骤:

1. 在Wagtail后台创建BlogTagIndexPage实例

BlogTagIndexPage只是页面模型,必须在后台实际创建该页面才能被访问:

  • 登录Wagtail管理后台
  • 找到你的博客索引页面(BlogIndexPage),点击添加子页面
  • 选择Blog Tag Index Page类型,标题可自定义(比如“标签归档”),但slug必须设置为tags(和模板中{% slugurl 'tags' %}的slug一致)
  • 保存并发布该页面

2. 确认项目URL路由配置正确

检查项目根目录的urls.py,确保已正确引入Wagtail的页面路由:

from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.documents import urls as wagtaildocs_urls

urlpatterns = [
    path('admin/', include(wagtailadmin_urls)),
    path('documents/', include(wagtaildocs_urls)),
    # 其他自定义路由...
    path('', include(wagtail_urls)),
]

这个配置让Wagtail处理所有页面的路由匹配,包括你创建的tags页面。

额外检查点

  • 确认创建的BlogTagIndexPage已发布,未发布页面无法通过前端访问
  • 核对模板中{% slugurl 'tags' %}生成的URL,必须和后台创建页面的slug完全匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 06:24:53