16
votes

The normal way sitemap is used in Django is:

from django.contrib.sitemaps import Sitemap
from schools.models import School


class SchoolSitemap(Sitemap):
    changefreq = "weekly"
    priority = 0.6

    def items(self):
        return School.objects.filter(status = 2)

and then in the model of School we define:

  def get_absolute_url(self):
      return reverse('schools:school_about', kwargs={'school_id': self.pk})

In such implementation I have one About link for one school in sitemap.xml

The problem is that my school has multiple pages: About, Teachers, Pupils and others and I would like all of the to be rendered is sitemap.xml

What is the best approach to do it?

1

1 Answers

12
votes

You can work with the fact that items may return anything that can be passed to the other methods of a Sitemap:

import itertools

class SchoolSitemap(Sitemap):
    # List method names from your objects that return the absolute URLs here
    FIELDS = ("get_absolute_url", "get_about_url", "get_teachers_url")

    changefreq = "weekly"
    priority = 0.6

    def items(self):
        # This will return you all possible ("method_name", object) tuples instead of the
        # objects from the query set. The documentation says that this should be a list 
        # rather than an iterator, hence the list() wrapper.
        return list(itertools.product(SchoolSitemap.FIELDS,
                                      School.objects.filter(status = 2)))

    def location(self, item):
        # Call method_name on the object and return its output
        return getattr(item[1], item[0])()

If the number and names of fields are not predetermined, I would go for a completely dynamic approach: Allow models to have a get_sitemap_urls method that returns a list of absolute URLs, and use a Sitemap that executes this method. That is, in the simplest case where you do not need to have access to the objects in the priority/changefreq/lastmod methods:

class SchoolSitemap(Sitemap):
    changefreq = "weekly"
    priority = 0.6

    def items(self):
        return list(
             itertools.chain.from_iterable(( object.get_sitemap_urls()
                                             for object in 
                                             School.objects.filter(status = 2)))
        )

    def location(self, item):
        return item