Handling Redirects and Sitemaps
To manage legacy URL migrations and provide search engines with structured site maps, this project provides the redirects and sitemaps applications. These tools allow you to handle 404 errors by redirecting to new content and generate XML sitemaps dynamically from your database.
Managing Redirects
To handle 404 errors by redirecting users to new paths, configure the RedirectFallbackMiddleware and manage entries in the Redirect model.
Configuring the Redirects App
The redirects application requires the sites framework to be installed. Add both to your INSTALLED_APPS and include the middleware at the end of your MIDDLEWARE list.
# settings.py
INSTALLED_APPS = [
"django.contrib.sites",
"django.contrib.redirects",
# ...
]
MIDDLEWARE = [
# ... other middleware ...
"django.contrib.redirects.middleware.RedirectFallbackMiddleware",
]
SITE_ID = 1
Creating Redirects
You can create redirects programmatically using the Redirect model. The RedirectFallbackMiddleware checks this model whenever a request results in a 404 response.
from django.contrib.redirects.models import Redirect
from django.contrib.sites.models import Site
# Create a 301 Permanent Redirect
Redirect.objects.create(
site=Site.objects.get_current(),
old_path="/old-page/",
new_path="/new-page/"
)
# Create a 410 Gone response (by leaving new_path empty)
Redirect.objects.create(
site=Site.objects.get_current(),
old_path="/obsolete-page/",
new_path=""
)
Customizing Redirect Behavior
If you need to return different status codes (e.g., 302 instead of 301), you can subclass RedirectFallbackMiddleware and override the response classes.
from django.contrib.redirects.middleware import RedirectFallbackMiddleware
from django.http import HttpResponseRedirect, HttpResponseForbidden
class CustomRedirectMiddleware(RedirectFallbackMiddleware):
# Use 302 Found instead of 301 Permanent Redirect
response_redirect_class = HttpResponseRedirect
# Use 403 Forbidden instead of 410 Gone
response_gone_class = HttpResponseForbidden
Generating Sitemaps
To generate XML sitemaps for search engines, use the Sitemap base class or the GenericSitemap helper.
Creating a Custom Sitemap
Define a class inheriting from Sitemap and implement the items() method. You can also provide location(), lastmod(), changefreq(), and priority().
from django.contrib.sitemaps import Sitemap
from myapp.models import Entry
class BlogSitemap(Sitemap):
changefreq = "never"
priority = 0.5
def items(self):
return Entry.objects.filter(is_public=True)
def lastmod(self, obj):
return obj.updated_at
def location(self, obj):
return f"/blog/{obj.slug}/"
Using GenericSitemap for QuerySets
For simple cases where you want to map a QuerySet directly, use GenericSitemap.
from django.contrib.sitemaps import GenericSitemap
from myapp.models import Product
info_dict = {
"queryset": Product.objects.all(),
"date_field": "last_modified",
}
product_sitemap = GenericSitemap(info_dict, priority=0.6, changefreq="weekly")
Routing Sitemaps in URLs
Wire your sitemaps into your URL configuration using the django.contrib.sitemaps.views.sitemap view.
from django.contrib.sitemaps import views
from django.urls import path
sitemaps = {
"blog": BlogSitemap,
"products": product_sitemap,
}
urlpatterns = [
path(
"sitemap.xml",
views.sitemap,
{"sitemaps": sitemaps},
name="django.contrib.sitemaps.views.sitemap",
),
]
Handling Internationalization (i18n)
The Sitemap class supports generating URLs for all enabled languages by setting i18n = True.
class MultilingualSitemap(Sitemap):
i18n = True
alternates = True
x_default = True
def items(self):
return MyModel.objects.all()
Troubleshooting and Gotchas
Missing Sites Framework
RedirectFallbackMiddleware will raise an ImproperlyConfigured error if django.contrib.sites is not in your INSTALLED_APPS. Both redirects and sitemaps rely on the Site model to resolve domains and associate paths.
Middleware Order
RedirectFallbackMiddleware only processes responses that have already been marked as 404. It should generally be placed near the end of your MIDDLEWARE list to ensure other views or middleware have had a chance to handle the request first.
Trailing Slashes
If settings.APPEND_SLASH is True, the middleware will attempt to match the requested path both as-is and with a trailing slash appended if the initial lookup fails.
Sitemap Limits
The Sitemap class enforces a limit of 50,000 items per page, as defined by the sitemap protocol. If your items() returns more than this, use the django.contrib.sitemaps.views.index view to create a sitemap index file.