Sitemap and object with multiple urls
Asked Answered
P

1

16

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?

Pas answered 12/2, 2017 at 11:11 Comment(0)
W
12

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
Whichsoever answered 15/2, 2017 at 10:39 Comment(3)
Thank you! You solution is working however I have changed it to fit my project because I have variable number of FIELDS for each model object.Pas
Good to hear. I'll amend the answer with how I'd solve the variable number of links case.Whichsoever
thank you one more time! I made it in the same way with object function and normal loops. you approach looks more elegant.Pas

© 2022 - 2024 — McMap. All rights reserved.