Карта сайта и объект с несколькими URL-адресами

В Django используется обычная карта sitemap:

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)

а затем в модели школы мы определяем:

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

В такой реализации у меня есть одна ссылка для одной школы в sitemap.xml

Проблема в том, что моя школа имеет несколько страниц: О, Учителя, Ученики и другие, и я бы хотел, чтобы все, что нужно было сделать, это sitemap.xml

Каков наилучший способ сделать это?

Ответы

Ответ 1

Вы можете работать с тем фактом, что items может возвращать все, что может быть передано другим методам 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])()

Если число и имена полей не заданы, я бы пошел на полностью динамический подход: разрешить модели иметь метод get_sitemap_urls, который возвращает список абсолютных URL-адресов, и использовать Sitemap, который выполняет этот метод, То есть, в простейшем случае, когда вам не нужно иметь доступ к объектам в методах priority/changefreq/lastmod:

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