Skip to main content

Advanced Sitemap Customization

The Sitemap class in django.contrib.sitemaps is designed as a flexible base for generating XML sitemaps. It provides a declarative interface where attributes can be either static values or callables, allowing for sophisticated logic when determining URL metadata like priority, modification dates, and internationalization alternates.

The Core Dispatcher: _get

The flexibility of the Sitemap class stems from its internal _get method. This method resolves attributes (such as location, priority, lastmod, and changefreq) by checking if they are callable.

def _get(self, name, item, default=None):
try:
attr = getattr(self, name)
except AttributeError:
return default
if callable(attr):
if self.i18n:
# Split the (item, lang_code) tuples again
item, lang_code = item
return attr(item)
return attr

If an attribute is a method, _get passes the current item to it. This allows you to define metadata dynamically based on the specific object being processed.

Defining Items and Locations

The two most fundamental methods to override are items() and location().

The items() Method

The items() method returns a list of objects. These objects are then passed to other methods (like location, lastmod, etc.) to build the sitemap entries. In django/contrib/flatpages/sitemaps.py, the FlatPageSitemap uses this to return a filtered QuerySet:

class FlatPageSitemap(Sitemap):
def items(self):
Site = django_apps.get_model("sites.Site")
current_site = Site.objects.get_current()
return current_site.flatpage_set.filter(registration_required=False)

The location() Method

By default, location() calls get_absolute_url() on the item. You can override this to provide custom URL logic:

def location(self, item):
return f"/custom-path/{item.slug}/"

Dynamic Metadata Control

Attributes like priority, changefreq, and lastmod can be defined as static class attributes or as methods for more granular control.

Priority and Change Frequency

In tests/sitemaps_tests/urls/http.py, the SimpleSitemap demonstrates static assignment:

class SimpleSitemap(Sitemap):
changefreq = "never"
priority = 0.5
location = "/location/"
# ...

For dynamic values, you can implement them as methods. For example, you might want higher priority for more recent items:

def priority(self, item):
return 1.0 if item.is_featured else 0.5

Last Modification (lastmod)

The lastmod attribute is critical for search engines to detect updates. If you provide a callable lastmod, the Sitemap class can calculate the latest_lastmod for the entire sitemap, which is used in sitemap index headers.

class CallableLastmodFullSitemap(Sitemap):
def items(self):
# Returns objects with a .lastmod attribute
return [obj1, obj2]

def lastmod(self, obj):
return obj.lastmod

The get_latest_lastmod() method iterates through all items to find the most recent date, provided that every item in the sitemap has a valid lastmod value.

Internationalization and Alternates

The Sitemap class includes built-in support for multi-lingual sites via the i18n, alternates, and x_default attributes.

When i18n = True, the internal _items() method transforms the list returned by items() into a list of (item, lang_code) tuples for every language defined in settings.LANGUAGES (or the languages attribute).

class AlternatesI18nSitemap(Sitemap):
i18n = True
alternates = True
x_default = True

def items(self):
return MyModel.objects.all()

How Alternates Work

If alternates is enabled, the _urls method generates <xhtml:link rel="alternate" ...> entries for each language.

  • i18n = True: Generates separate <url> entries for each language version of an item.
  • alternates = True: Adds hreflang links within each <url> entry pointing to other language versions.
  • x_default = True: Adds an x-default hreflang link using the settings.LANGUAGE_CODE.

Scaling and Pagination

To handle large datasets, the Sitemap class implements pagination using the limit attribute, which defaults to 50,000 (the maximum allowed by the sitemap protocol).

class LargeSitemap(Sitemap):
limit = 10000 # Smaller chunks for faster processing

def items(self):
return BigModel.objects.all().order_by('id')

The paginator property automatically handles the slicing of the items() list based on this limit. When a sitemap is accessed via a view, the page parameter determines which subset of items is processed by get_urls().

Domain and Protocol Resolution

The Sitemap class relies on the sites framework to determine the domain name. The get_domain() method attempts to fetch the current site:

def get_domain(self, site=None):
if site is None:
if django_apps.is_installed("django.contrib.sites"):
Site = django_apps.get_model("sites.Site")
site = Site.objects.get_current()
return site.domain

If django.contrib.sites is not installed, you must pass a Site or RequestSite object to the sitemap view, otherwise an ImproperlyConfigured exception is raised. The protocol defaults to https unless the protocol attribute is explicitly set to http.