WDTutorials.com Become A Professional
Software Developer.

Django - Sitemap Tutorial (Python)

How to create XML sitemaps with Django sitemap framework.

Updated May 6, 2024

Table of contents

You will learn

  • How to add dynamic and static pages to your sitemap:
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>http://example.com/blog/blog-1/</loc>
        <lastmod>2024-12-24</lastmod>
    </url>
    <url>
        <loc>http://example.com/about/</loc>
    </url>
</urlset>

Settings

Edit settings.py and add these lines:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites', # here
    'django.contrib.sitemaps', # here
    'blog',
]

SITE_ID = 1 # here
  • The sites framework allows you to manage multiple sites from a single installation. The sitemaps framework needs it to work properly.
  • SITE_ID specifies the ID of the current site. 1 is the ID of the default Site object.

Update a model

Edit a model and add a modified field to it. Make sure that your model has the get_absolute_url() method:

from django.db import models
from django.urls import reverse


class Post(models.Model):
    title = models.CharField(max_length=255, blank=False, default='')
    body = models.TextField(blank=False, default='')
    slug = models.SlugField(max_length=255, blank=False, unique=True)
    modified = models.DateTimeField(auto_now=True) # here

    def __str__(self):
        return self.title

    # here
    def get_absolute_url(self):
        return reverse('blog:post_detail', args=[self.slug])
  • The modified field is used for the sitemap lastmod attribute.
  • auto_now=True specifies that the field should be automatically set to the current date and time when the object is created or updated.

Run migrations:

python manage.py makemigrations
python manage.py migrate

Sitemap entries for blog posts

Edit urls.py and add these lines:

from django.contrib import admin
from django.urls import include, path
from blog.models import Post # here
from django.contrib.sitemaps import GenericSitemap # here
from django.contrib.sitemaps.views import sitemap # here

# start
sitemaps = {
    'blog': GenericSitemap({
        'queryset': Post.objects.all(),
        'date_field': 'modified',
    }),
}
# end

urlpatterns = [
    path('blog/', include('blog.urls')),
    path('admin/', admin.site.urls),
    # here
    path('sitemap.xml', sitemap,
         {'sitemaps': sitemaps},
         name='django.contrib.sitemaps.views.sitemap'),
]
  • The GenericSitemap convenience class allows you to create basic sitemaps by passing it a queryset entry.

Visit /sitemap.xml and you should see something like this:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>http://example.com/blog/blog-1/</loc>
        <lastmod>2024-12-24</lastmod>
    </url>
    <url>
        <loc>http://example.com/blog/blog-2/</loc>
        <lastmod>2024-12-25</lastmod>
    </url>
</urlset>

Sitemap entries for static pages

Let's add /about/ page to the sitemap. Edit urls.py and make these changes:

from django.contrib import admin
from django.urls import include, path, reverse # import reverse
from blog.models import Post
from django.contrib.sitemaps import GenericSitemap
from django.contrib.sitemaps.views import sitemap
from django.contrib.sitemaps import Sitemap # here
from django.views.generic import TemplateView # here


# start
class StaticViewSitemap(Sitemap):
    def items(self):
        return ['about']

    def location(self, item):
        return reverse(item)
# end

sitemaps = {
    'blog': GenericSitemap({
        'queryset': Post.objects.all(),
        'date_field': 'modified',
    }),
    'static': StaticViewSitemap, # here
}

urlpatterns = [
    path('blog/', include('blog.urls')),
    path('admin/', admin.site.urls),
    # here:
    path('about/', TemplateView.as_view(template_name='about.html'), name='about'),
    path('sitemap.xml', sitemap,
         {'sitemaps': sitemaps},
         name='django.contrib.sitemaps.views.sitemap'),
]
  • The Sitemap class provides more control over the creation of sitemaps, but it requires you to create a dedicated class.

Create templates/about.html:

<div class="about">
    <h1>About</h1>
    <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. 
    </p>
</div>

For Django to find templates in the templates directory, you should add it to the DIRS setting in settings.py:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backen...',
        'DIRS': [BASE_DIR / 'templates'], # here
        'APP_DIRS': True,
        # ..
    },
]

Visit /sitemap.xml:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>http://example.com/blog/blog-1/</loc>
        <lastmod>2024-12-24</lastmod>
    </url>
    <url>
        <loc>http://example.com/blog/blog-2/</loc>
        <lastmod>2024-12-25</lastmod>
    </url>
    <url>
        <loc>http://example.com/about/</loc>
    </url>
</urlset>

Specify domain in production

In production, make sure to update the Site object to match your domain:

Leave a comment

You can use Markdown to format your comment.