This app aims to provide the missing XML sitemapsf for Django. At the moment the following XML sitemaps are implemented:

  • qartez.sitemaps.ImagesSitemap: XML images sitemaps according to the specs.
  • qartez.sitemaps.StaticSitemap: Sitemap for service pages. Add named patterns or URLs to the sitemap to have it nicely displayed in a separate service XML sitemap.
  • qartez.sitemaps.RelAlternateHreflangSitemap: Sitemaps: rel="alternate" hreflang="x" implementation. Read the specs.


  • Django: 1.8, 1.9, 1.10, 1.11
  • Python: 2.7, 3.4, 3.5, 3.6


1. Install

Latest stable version on PyPI:

pip install django-qartez

Latest stable version from BitBucket:

pip install

Latest stable version from GitHub:

pip install

2. Add qartez to your INSTALLED_APPS

    # ...
    # ...

Usage and examples

We have an imaginary foo app.

The full source code of the example below here (see the example directory).


from django.contrib.sitemaps import Sitemap

from qartez.sitemaps import (
   ImagesSitemap, StaticSitemap, RelAlternateHreflangSitemap

from foo.models import FooItem

# ---------------------- XML images sitemap part ---------------------------
# Dictionary to feed to the images sitemap.
foo_item_images_info_dict = {
    # Base queryset to iterate when procuding a site map
    'queryset': FooItem._default_manager.exclude(image=None),
    'image_location_field': 'image_url', # Image location (URL)
    'image_title_field': 'title', # Image title
    # An absolute URL of the page where image is shown
    'location_field': 'get_absolute_url'

# XML images sitemap.
foo_item_images_sitemap = {
    'foo_item_images': ImagesSitemap(foo_item_images_info_dict,

# ---------------------- Static sitemap part ---------------------------
# Sitemap for service pages like welcome and feedback.
foo_static_sitemap = StaticSitemap(priority=0.1, changefreq='never')

# ---------------------- Normal sitemap part ---------------------------
# Normal Foo items sitemap.
class FooItemSitemap(Sitemap):
    changefreq = "weekly"
    priority = 1.0

    def location(self, obj):
       return obj.get_absolute_url()

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

    def items(self):
       return FooItem._default_manager.all()

# ---------------------- Alternate hreflang sitemap part ---------------
# Alternate hreflang sitemap.
class ArticleSitemap(RelAlternateHreflangSitemap):
    # If you want to serve the links on HTTPS.
    protocol = 'https'

    def alternate_hreflangs(self, obj):
       return [('en-us', obj.alternative_object_url),]

    def items(self):
       return FooItem._default_manager.all()

from foo.sitemap import foo_item_images_sitemap, foo_static_sitemap
from foo.sitemap import FooItemAlternateHreflangSitemap, FooItemSitemap

sitemaps = {
    'foo-items': FooItemSitemap,
    'foo-items-alternate-hreflang': FooItemAlternateHreflangSitemap,
    'foo-static': foo_static_sitemap

urlpatterns = patterns('',
    # Sitemaps
    (r'^sitemap\.xml$', 'django.contrib.sitemaps.views.index', \
    {'sitemaps': sitemaps}),

    (r'^sitemap-foo-images\.xml$', 'qartez.views.render_images_sitemap', \
    {'sitemaps': foo_item_images_sitemap}),

Note, that it's necessary to add the 'template_name': 'qartez/rel_alternate_hreflang_sitemap.xml' only in case if you are going to use the qartez.RelAlternateHreflangSitemap.

        'sitemaps': sitemaps,
        'template_name': 'qartez/rel_alternate_hreflang_sitemap.xml'

In order to just get a better idea what kind of models and views are given in the example, see the code parts below.


class FooItem(models.Model):
    title = models.CharField(_("Title"), max_length=100)
    slug = models.SlugField(_("Slug"), unique=True)
    body = models.TextField(_("Body"))
    date_published = models.DateTimeField(_("Date published"), blank=True,

    # Image to be used for XML images sitemap.
    image = models.ImageField(_("Headline image"), blank=True, null=True,

    # URL to be used for alternative hreflang attribute.
    alternative_url = models.URLField(_("Alternative URL"), blank=True,

    class Meta:
       verbose_name = _("Foo item")
       verbose_name_plural = _("Foo items")

    def __unicode__(self):
       return self.title

    def get_absolute_url(self):
       kwargs = {'slug': self.slug}
       return reverse('foo.detail', kwargs=kwargs)

    # Shortcut to full image URL for XML images sitemap.
    def image_url(self):
       return self.image.url if self.image else ''


# Service welcome page
def welcome(request, template_name='foo/welcome.html'):
    context = {}
    return render_to_response(template_name, context, \

# Service contact page
def contact(request, template_name='foo/contact.html'):
    context = {}
    return render_to_response(template_name, context, \


urlpatterns = patterns('foo.views',
    # ...
    # Contact URL
    url(r'^contact/$', view='contact', name=''),
    # ...
    # Welcome URL
    url(r'^welcome/$', view='welcome', name='foo.welcome'),
    # ...


GPL 2.0/LGPL 2.1


For any issues contact me at the e-mail given in the Author section.


Artur Barseghyan <>