Create a Sitemap (SiteMap.xml) in Django
Our application's sitemap is very simple, but before implementing it, I want you to get some context and understand why we're doing all this.
The sitemap is basically a file that contains a list of our site's URLs. I have a couple of posts here, which is why you only see two. The main domain appears at the top, but that's up to you. The important thing is the content of the file, not so much the domain.
What is a sitemap?
In case you're unfamiliar, a sitemap is a file (usually an XML file) that tells search engines—like Google—what pages your site contains. This allows them to navigate your content without having to crawl the entire HTML, accessing the listed URLs directly.
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>https://www.desarrollolibre.net</loc>
</url>
</urlset>
Typically, only URLs we want to index, such as relevant posts or pages, are placed in this file. Listing pages are typically not included, as they don't contribute as much from an SEO perspective.
Sitemap structure (XML)
The sitemap is simply an XML file with a specific structure. These are the tags used. You can add more options, such as:
- Update frequency.
- Expiration date.
- Priority.
Generally, the sitemap should be in the root of the site (/sitemap.xml). However, in this exercise, I placed it within the blog application, as that's how I structure the project.
There is excellent documentation on this, such as Mozilla's, that can help you if you want to dig deeper.
In this exercise, I'm using the simplest version of the XML because I don't want to overcomplicate the example.
If you wanted to move it, you would have to modify the URLs where you're generating it. In my case, I don't mind having it in a subpath, since we also declare it in the robots.txt file, indicating where the sitemap is located.
Implementing the sitemap in Django
Now, let's see how it is implemented.
1. Generate the URL for each post
One challenge we faced was that Django doesn't provide us with the BASE_URL directly. At least, not easily. So we generated it manually and used it to create each URL in the sitemap:
class PostSitemap(ListView):
model = Post
context_object_name = 'posts'
template_name = 'post/sitemap.html'
def render_to_response(self, context, **response_kwargs):
response_kwargs['content_type'] = 'application/xml'
context['base_url'] = self.request.build_absolute_uri('/').rstrip('/')
return super().render_to_response(context, **response_kwargs)
In the Post model, I declared a method called get_url (or something similar, like getRoute). This method generates the URL based on the route name and the post slug. Django Templates have certain limitations when generating URLs (such as using reverse), so this method makes things much easier for us from the template:
class Post(models.Model):
def getRoute(self):
return reverse("b.show", args=[self.slug])
2. Create the view that returns the XML
We created a class-based view very similar to the one we used for the listings. The key differences are:
- Changing the Content-Type of the response to application/xml.
- Passing the base_url as part of the context.
Additionally, we used render_to_response() to customize the final response and add additional context. A technical detail: I removed the trailing slash from the base_url because the slugs already include it, and I didn't want to have double slashes (//) in the URLs.
3. Sitemap template
The template is an XML file where we use Django's template engine. Here:
- We declare the sitemap structure (<urlset> and <url>).
- We use filters like add (|add) to concatenate strings.
- We iterate over the posts and generate each URL by combining the base_url with the post's route method.
I've also left comments in the template so you can test it or modify it if you want to change anything.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
{% comment %} <loc>{{ request.build_absolute_uri|add:"/" }}</loc> {% endcomment %}
<loc>{{ base_url }}</loc>
</url>
{% for post in posts %}
<url>
<loc>{{ base_url|add:post.getRoute }}</loc>
</url>
{% endfor %}
</urlset>
When you access the corresponding path, you'll see the generated XML with the post URLs. You can verify that the Content-Type is application/xml, which is important for the browser or bots to interpret it correctly.
With this, you have your sitemap implemented in Django. It's simple, functional, and easy to maintain. Ideal for getting started with good practices regarding SEO and site structuring.
I agree to receive announcements of interest about this Blog.
I show you how to create a Sitemap in a Django app with class-based views.
- Andrés Cruz