123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- from urllib.parse import urlencode
- from urllib.request import urlopen
-
- from django.apps import apps as django_apps
- from django.conf import settings
- from django.core import paginator
- from django.core.exceptions import ImproperlyConfigured
- from django.urls import NoReverseMatch, reverse
- from django.utils import translation
-
- PING_URL = "https://www.google.com/webmasters/tools/ping"
-
-
- class SitemapNotFound(Exception):
- pass
-
-
- def ping_google(sitemap_url=None, ping_url=PING_URL, sitemap_uses_https=True):
- """
- Alert Google that the sitemap for the current site has been updated.
- If sitemap_url is provided, it should be an absolute path to the sitemap
- for this site -- e.g., '/sitemap.xml'. If sitemap_url is not provided, this
- function will attempt to deduce it by using urls.reverse().
- """
- sitemap_full_url = _get_sitemap_full_url(sitemap_url, sitemap_uses_https)
- params = urlencode({'sitemap': sitemap_full_url})
- urlopen('%s?%s' % (ping_url, params))
-
-
- def _get_sitemap_full_url(sitemap_url, sitemap_uses_https=True):
- if not django_apps.is_installed('django.contrib.sites'):
- raise ImproperlyConfigured("ping_google requires django.contrib.sites, which isn't installed.")
-
- if sitemap_url is None:
- try:
- # First, try to get the "index" sitemap URL.
- sitemap_url = reverse('django.contrib.sitemaps.views.index')
- except NoReverseMatch:
- try:
- # Next, try for the "global" sitemap URL.
- sitemap_url = reverse('django.contrib.sitemaps.views.sitemap')
- except NoReverseMatch:
- pass
-
- if sitemap_url is None:
- raise SitemapNotFound("You didn't provide a sitemap_url, and the sitemap URL couldn't be auto-detected.")
-
- Site = django_apps.get_model('sites.Site')
- current_site = Site.objects.get_current()
- scheme = 'https' if sitemap_uses_https else 'http'
- return '%s://%s%s' % (scheme, current_site.domain, sitemap_url)
-
-
- class Sitemap:
- # This limit is defined by Google. See the index documentation at
- # https://www.sitemaps.org/protocol.html#index.
- limit = 50000
-
- # If protocol is None, the URLs in the sitemap will use the protocol
- # with which the sitemap was requested.
- protocol = None
-
- def __get(self, name, obj, default=None):
- try:
- attr = getattr(self, name)
- except AttributeError:
- return default
- if callable(attr):
- return attr(obj)
- return attr
-
- def items(self):
- return []
-
- def location(self, obj):
- return obj.get_absolute_url()
-
- @property
- def paginator(self):
- return paginator.Paginator(self.items(), self.limit)
-
- def get_urls(self, page=1, site=None, protocol=None):
- # Determine protocol
- if self.protocol is not None:
- protocol = self.protocol
- if protocol is None:
- protocol = 'http'
-
- # Determine domain
- if site is None:
- if django_apps.is_installed('django.contrib.sites'):
- Site = django_apps.get_model('sites.Site')
- try:
- site = Site.objects.get_current()
- except Site.DoesNotExist:
- pass
- if site is None:
- raise ImproperlyConfigured(
- "To use sitemaps, either enable the sites framework or pass "
- "a Site/RequestSite object in your view."
- )
- domain = site.domain
-
- if getattr(self, 'i18n', False):
- urls = []
- current_lang_code = translation.get_language()
- for lang_code, lang_name in settings.LANGUAGES:
- translation.activate(lang_code)
- urls += self._urls(page, protocol, domain)
- translation.activate(current_lang_code)
- else:
- urls = self._urls(page, protocol, domain)
-
- return urls
-
- def _urls(self, page, protocol, domain):
- urls = []
- latest_lastmod = None
- all_items_lastmod = True # track if all items have a lastmod
- for item in self.paginator.page(page).object_list:
- loc = "%s://%s%s" % (protocol, domain, self.__get('location', item))
- priority = self.__get('priority', item)
- lastmod = self.__get('lastmod', item)
- if all_items_lastmod:
- all_items_lastmod = lastmod is not None
- if (all_items_lastmod and
- (latest_lastmod is None or lastmod > latest_lastmod)):
- latest_lastmod = lastmod
- url_info = {
- 'item': item,
- 'location': loc,
- 'lastmod': lastmod,
- 'changefreq': self.__get('changefreq', item),
- 'priority': str(priority if priority is not None else ''),
- }
- urls.append(url_info)
- if all_items_lastmod and latest_lastmod:
- self.latest_lastmod = latest_lastmod
- return urls
-
-
- class GenericSitemap(Sitemap):
- priority = None
- changefreq = None
-
- def __init__(self, info_dict, priority=None, changefreq=None, protocol=None):
- self.queryset = info_dict['queryset']
- self.date_field = info_dict.get('date_field')
- self.priority = priority
- self.changefreq = changefreq
- self.protocol = protocol
-
- def items(self):
- # Make sure to return a clone; we don't want premature evaluation.
- return self.queryset.filter()
-
- def lastmod(self, item):
- if self.date_field is not None:
- return getattr(item, self.date_field)
- return None
-
-
- default_app_config = 'django.contrib.sitemaps.apps.SiteMapsConfig'
|