You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

__init__.py 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. from urllib.parse import urlencode
  2. from urllib.request import urlopen
  3. from django.apps import apps as django_apps
  4. from django.conf import settings
  5. from django.core import paginator
  6. from django.core.exceptions import ImproperlyConfigured
  7. from django.urls import NoReverseMatch, reverse
  8. from django.utils import translation
  9. PING_URL = "https://www.google.com/webmasters/tools/ping"
  10. class SitemapNotFound(Exception):
  11. pass
  12. def ping_google(sitemap_url=None, ping_url=PING_URL, sitemap_uses_https=True):
  13. """
  14. Alert Google that the sitemap for the current site has been updated.
  15. If sitemap_url is provided, it should be an absolute path to the sitemap
  16. for this site -- e.g., '/sitemap.xml'. If sitemap_url is not provided, this
  17. function will attempt to deduce it by using urls.reverse().
  18. """
  19. sitemap_full_url = _get_sitemap_full_url(sitemap_url, sitemap_uses_https)
  20. params = urlencode({'sitemap': sitemap_full_url})
  21. urlopen('%s?%s' % (ping_url, params))
  22. def _get_sitemap_full_url(sitemap_url, sitemap_uses_https=True):
  23. if not django_apps.is_installed('django.contrib.sites'):
  24. raise ImproperlyConfigured("ping_google requires django.contrib.sites, which isn't installed.")
  25. if sitemap_url is None:
  26. try:
  27. # First, try to get the "index" sitemap URL.
  28. sitemap_url = reverse('django.contrib.sitemaps.views.index')
  29. except NoReverseMatch:
  30. try:
  31. # Next, try for the "global" sitemap URL.
  32. sitemap_url = reverse('django.contrib.sitemaps.views.sitemap')
  33. except NoReverseMatch:
  34. pass
  35. if sitemap_url is None:
  36. raise SitemapNotFound("You didn't provide a sitemap_url, and the sitemap URL couldn't be auto-detected.")
  37. Site = django_apps.get_model('sites.Site')
  38. current_site = Site.objects.get_current()
  39. scheme = 'https' if sitemap_uses_https else 'http'
  40. return '%s://%s%s' % (scheme, current_site.domain, sitemap_url)
  41. class Sitemap:
  42. # This limit is defined by Google. See the index documentation at
  43. # https://www.sitemaps.org/protocol.html#index.
  44. limit = 50000
  45. # If protocol is None, the URLs in the sitemap will use the protocol
  46. # with which the sitemap was requested.
  47. protocol = None
  48. def __get(self, name, obj, default=None):
  49. try:
  50. attr = getattr(self, name)
  51. except AttributeError:
  52. return default
  53. if callable(attr):
  54. return attr(obj)
  55. return attr
  56. def items(self):
  57. return []
  58. def location(self, obj):
  59. return obj.get_absolute_url()
  60. @property
  61. def paginator(self):
  62. return paginator.Paginator(self.items(), self.limit)
  63. def get_urls(self, page=1, site=None, protocol=None):
  64. # Determine protocol
  65. if self.protocol is not None:
  66. protocol = self.protocol
  67. if protocol is None:
  68. protocol = 'http'
  69. # Determine domain
  70. if site is None:
  71. if django_apps.is_installed('django.contrib.sites'):
  72. Site = django_apps.get_model('sites.Site')
  73. try:
  74. site = Site.objects.get_current()
  75. except Site.DoesNotExist:
  76. pass
  77. if site is None:
  78. raise ImproperlyConfigured(
  79. "To use sitemaps, either enable the sites framework or pass "
  80. "a Site/RequestSite object in your view."
  81. )
  82. domain = site.domain
  83. if getattr(self, 'i18n', False):
  84. urls = []
  85. current_lang_code = translation.get_language()
  86. for lang_code, lang_name in settings.LANGUAGES:
  87. translation.activate(lang_code)
  88. urls += self._urls(page, protocol, domain)
  89. translation.activate(current_lang_code)
  90. else:
  91. urls = self._urls(page, protocol, domain)
  92. return urls
  93. def _urls(self, page, protocol, domain):
  94. urls = []
  95. latest_lastmod = None
  96. all_items_lastmod = True # track if all items have a lastmod
  97. for item in self.paginator.page(page).object_list:
  98. loc = "%s://%s%s" % (protocol, domain, self.__get('location', item))
  99. priority = self.__get('priority', item)
  100. lastmod = self.__get('lastmod', item)
  101. if all_items_lastmod:
  102. all_items_lastmod = lastmod is not None
  103. if (all_items_lastmod and
  104. (latest_lastmod is None or lastmod > latest_lastmod)):
  105. latest_lastmod = lastmod
  106. url_info = {
  107. 'item': item,
  108. 'location': loc,
  109. 'lastmod': lastmod,
  110. 'changefreq': self.__get('changefreq', item),
  111. 'priority': str(priority if priority is not None else ''),
  112. }
  113. urls.append(url_info)
  114. if all_items_lastmod and latest_lastmod:
  115. self.latest_lastmod = latest_lastmod
  116. return urls
  117. class GenericSitemap(Sitemap):
  118. priority = None
  119. changefreq = None
  120. def __init__(self, info_dict, priority=None, changefreq=None, protocol=None):
  121. self.queryset = info_dict['queryset']
  122. self.date_field = info_dict.get('date_field')
  123. self.priority = priority
  124. self.changefreq = changefreq
  125. self.protocol = protocol
  126. def items(self):
  127. # Make sure to return a clone; we don't want premature evaluation.
  128. return self.queryset.filter()
  129. def lastmod(self, item):
  130. if self.date_field is not None:
  131. return getattr(item, self.date_field)
  132. return None
  133. default_app_config = 'django.contrib.sitemaps.apps.SiteMapsConfig'