Error handlingยค
The built-in ErrorFallback
component catches errors during component rendering and displays fallback content instead. This is similar to React's ErrorBoundary
component.
In this scenario, we have a WeatherWidget
component that simulates fetching data from a weather API, which we wrap in the built-in ErrorFallback
component.
We have two cases:
- API call succeeds. The
WeatherWidget
component renders the weather information as expected. - API call fails. The
ErrorFallback
component catches the error and display a user-friendly message instead of breaking the page.
{% component "error_fallback" %}
{% fill "content" %}
{% component "weather_widget" location="Atlantis" / %}
{% endfill %}
{% fill "fallback" %}
<p style="color: red;">
Could not load weather data for <strong>Atlantis</strong>.
The location may not be supported or the service is temporarily down.
</p>
{% endfill %}
{% endcomponent %}
Definitionยค
# ruff: noqa: S311
import random
from typing import NamedTuple
from django_components import Component, register, types
DESCRIPTION = "A component that catches errors and displays fallback content, similar to React's ErrorBoundary."
@register("weather_widget")
class WeatherWidget(Component):
class Kwargs(NamedTuple):
location: str
simulate_error: bool = False
def get_template_data(self, args, kwargs: Kwargs, slots, context):
if kwargs.simulate_error:
raise OSError(f"Failed to connect to weather service for '{kwargs.location}'.")
return {
"location": kwargs.location,
"temperature": f"{random.randint(10, 30)}ยฐC",
"condition": random.choice(["Sunny", "Cloudy", "Rainy"]),
}
template: types.django_html = """
<div class="bg-white rounded-lg shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-800 mb-2">
Weather in {{ location }}
</h3>
<p class="text-gray-600">
<strong class="font-medium text-gray-700">Temperature:</strong>
{{ temperature }}
</p>
<p class="text-gray-600">
<strong class="font-medium text-gray-700">Condition:</strong>
{{ condition }}
</p>
</div>
"""
Exampleยค
To see the component in action, you can set up a view and URL pattern as shown below.
views.py
ยค
from django.http import HttpRequest, HttpResponse
from django.utils.safestring import mark_safe
from django_components import Component, types
class ErrorFallbackPage(Component):
class Media:
js = (
mark_safe(
'<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,line-clamp,container-queries"></script>'
),
)
template: types.django_html = """
{% load component_tags %}
<html>
<head>
<title>ErrorFallback Example</title>
</head>
<body class="bg-gray-100 p-8">
<div class="max-w-2xl mx-auto bg-white p-6 rounded-lg shadow-md">
<h1 class="text-2xl font-bold mb-4">Weather API Widget Example</h1>
<p class="text-gray-600 mb-6">
This example demonstrates using ErrorFallback to handle potential API failures gracefully.
</p>
<div class="mb-8">
<h2 class="text-xl font-semibold mb-2">Case 1: API call is successful</h2>
{% component "error_fallback" %}
{% fill "content" %}
{% component "weather_widget" location="New York" / %}
{% endfill %}
{% fill "fallback" %}
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
<strong class="font-bold">Error:</strong>
<span class="block sm:inline">Could not load weather data.</span>
</div>
{% endfill %}
{% endcomponent %}
</div>
<div>
<h2 class="text-xl font-semibold mb-2">Case 2: API call fails</h2>
{% component "error_fallback" %}
{% fill "content" %}
{% component "weather_widget" location="Atlantis" simulate_error=True / %}
{% endfill %}
{% fill "fallback" %}
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
<strong class="font-bold">Error:</strong>
<span class="block sm:inline">
Could not load weather data for
<strong>Atlantis</strong>.
The location may not be supported or the service is temporarily down.
</span>
</div>
{% endfill %}
{% endcomponent %}
</div>
</div>
</body>
</html>
""" # noqa: E501
class View:
def get(self, request: HttpRequest) -> HttpResponse:
return ErrorFallbackPage.render_to_response(request=request)