Wagtail页面异常处理

后端开发 2026-07-11

我们有一个Wagtail页面模型,主要由以下部分组成

get_context方法,用于检索数据
我们需要在发生错误时将用户重定向到错误页面

检索这些数据
如何实现这一点——我的尝试导致了

"get_context必须返回一个字典" 的错误
提前致谢

解决方案

来自 get_context() 的期望返回值是一个上下文项的字典对象。该错误最有可能来自Page模型 serve() 方法:

    def serve(self, request, *args, **kwargs):
        request.is_preview = False

        return TemplateResponse(
            request,
            self.get_template(request, *args, **kwargs),
            self.get_context(request, *args, **kwargs),
        )

如果你从 get_context 返回一个重定向响应,那么这会给 TemplateResponse 传递一个意外的值类型。

假设你想要一个带有上下文消息的自定义错误页,有几种处理方式浮现在脑海:模板分支逻辑;在你的页面模型中覆盖 serve() 方法(这里有几个选项:重定向或更改模板);使用 RoutablePageMixin,它为你提供了一种干净的方式来操作渲染后的页面,而不干扰wagtail的核心方法。

假设你有一个携带收集到的错误信息的上下文变量:

模板逻辑

使用一个包装模板,根据errors上下文变量是否为真来包含相应的模板代码:

{% if found_errors %}
    {% include "pages/custom_error_template.html" %}
{% else %}
    {% include "pages/custom_page_content.html" %}
{% endif %}

这是最简单的选项。

自定义serve()

  1. 重定向

为了在重定向时传递错误信息,你需要使用类似Django messages的机制,因为上下文在重定向时会丢失:

from django.contrib import messages
from django.shortcuts import redirect
from wagtail.models import Page

class CustomPage(Page):
    template = "pages/custom_page.html"

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        errors = []

        try:
            # Some code that may raise exceptions
            ...
        except Exception as e:
            errors.append(list(e.args))

        isValid, validation_errors = self.validate_data() # custom validation method
        if not isValid: 
            errors.extend(validation_errors)

        context["found_errors"] = errors
        return context      

    def serve(self, request):
        context = self.get_context(request)

        if context["found_errors"]:
            for err in context["found_errors"]:
                messages.error(request, err)

            return redirect("/error-page/")

        return self.render(request, context)

模板:

{% if messages %}
    <ul class="messages">
        {% for message in messages %}
            <li class="{{ message.tags }}">
                {{ message }}
            </li>
        {% endfor %}
    </ul>
{% endif %}

你还需要处理那个重定向路径(urls/view等等)。

  1. 相同的URL,条件模板路径
def serve(self, request):
    context = self.get_context(request)

    if context["found_errors"]:
        return self.render(
            request,
            context=context,
            template="pages/custom_error_template.html",
        )

    return self.render(request, context)

RoutablePageMixin

这避免了覆盖核心serve方法的需要。

  1. self.render() 中有条件地设置模板:
class CustomPage(RoutablePageMixin, Page):
    template = "pages/custom_page.html"
    error_template = "pages/custom_error_template.html"

    def get_context_overrides(self, request, *args, **kwargs):
        errors = []
        try:
            # Some code that may raise exceptions
            ...
        except Exception as e:
            errors.append(list(e.args))

        isValid, validation_errors = self.validate_data() # custom validation method
        if not isValid: 
            errors.extend(validation_errors)

        context_overrides["found_errors"] = errors
        return context_overrides

    @path("")
    def main_view(self, request):
        """Default page rendering"""
        context_overrides = self.get_context_overrides(request)
        template = self.error_template if context_overrides["found_errors"] else self.template
        return self.render(request, context_overrides, template)
  1. 使用一个错误路径来显示标准错误类型的固定消息
class CustomPage(RoutablePageMixin, Page):
    template = "pages/custom_page.html"
    error_template = "pages/custom_error_template.html"

    def get_context_overrides(self, request, *args, **kwargs):
        try:
            context_overrides = {...}
            isValid, validation_error_type = self.validate_data() # custom validation method
            if not isValid: 
                context_overrides["found_error"] = validation_error_type 
        except Exception as e:
            context_overrides["found_error"] = type(e).__name__
        return context_overrides

    @path("")
    def main_view(self, request):
        """Default page rendering"""
        context_overrides = self.get_context_overrides(request)

        if context_overrides["found_error"]:
            return redirect(self.reverse_subpage("error_view", args=[context_overrides["found_error"]]))

        return self.render(request, context_overrides, self.template)

    @path("error/<code:str>")
    def error_view(self, request, code):
        """Render error page based on standard error code"""

        # Map error codes to human-readable messages
        error_messages = {
            "no_data": "No data available for this page.",
            "permission_denied": "You do not have permission to view this page.",
            # Add more standard codes here
        }
        context_overrides = {
            "message": error_messages.get(code, "Unknown error occurred.")
        }

        return self.render(request, context_overrides, self.error_template)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章