from django.apps import apps from django.contrib.gis.db.models import GeometryField from django.contrib.sitemaps import Sitemap from django.db import models from django.urls import reverse class KMLSitemap(Sitemap): """ A minimal hook to produce KML sitemaps. """ geo_format = 'kml' def __init__(self, locations=None): # If no locations specified, then we try to build for # every model in installed applications. self.locations = self._build_kml_sources(locations) def _build_kml_sources(self, sources): """ Go through the given sources and return a 3-tuple of the application label, module name, and field name of every GeometryField encountered in the sources. If no sources are provided, then all models. """ kml_sources = [] if sources is None: sources = apps.get_models() for source in sources: if isinstance(source, models.base.ModelBase): for field in source._meta.fields: if isinstance(field, GeometryField): kml_sources.append((source._meta.app_label, source._meta.model_name, field.name)) elif isinstance(source, (list, tuple)): if len(source) != 3: raise ValueError('Must specify a 3-tuple of (app_label, module_name, field_name).') kml_sources.append(source) else: raise TypeError('KML Sources must be a model or a 3-tuple.') return kml_sources def get_urls(self, page=1, site=None, protocol=None): """ This method is overridden so the appropriate `geo_format` attribute is placed on each URL element. """ urls = Sitemap.get_urls(self, page=page, site=site, protocol=protocol) for url in urls: url['geo_format'] = self.geo_format return urls def items(self): return self.locations def location(self, obj): return reverse( 'django.contrib.gis.sitemaps.views.%s' % self.geo_format, kwargs={ 'label': obj[0], 'model': obj[1], 'field_name': obj[2], }, ) class KMZSitemap(KMLSitemap): geo_format = 'kmz'