/feincms/module/page/sitemap.py

http://github.com/feincms/feincms · Python · 131 lines · 73 code · 19 blank · 39 comment · 24 complexity · 75237dcdb9372677dea99ca12f5c81d5 MD5 · raw file

  1. # ------------------------------------------------------------------------
  2. # coding=utf-8
  3. # ------------------------------------------------------------------------
  4. from __future__ import absolute_import, unicode_literals
  5. from django.apps import apps
  6. from django.db.models import Max
  7. from django.contrib.sitemaps import Sitemap
  8. from feincms import settings
  9. # ------------------------------------------------------------------------
  10. class PageSitemap(Sitemap):
  11. """
  12. The PageSitemap can be used to automatically generate sitemap.xml files
  13. for submission to index engines. See http://www.sitemaps.org/ for details.
  14. """
  15. def __init__(
  16. self,
  17. navigation_only=False,
  18. max_depth=0,
  19. changefreq=None,
  20. queryset=None,
  21. filter=None,
  22. extended_navigation=False,
  23. page_model=settings.FEINCMS_DEFAULT_PAGE_MODEL,
  24. *args,
  25. **kwargs
  26. ):
  27. """
  28. The PageSitemap accepts the following parameters for customisation
  29. of the resulting sitemap.xml output:
  30. * navigation_only -- if set to True, only pages that are in_navigation
  31. will appear in the site map.
  32. * max_depth -- if set to a non-negative integer, will limit the sitemap
  33. generated to this page hierarchy depth.
  34. * changefreq -- should be a string or callable specifiying the page
  35. update frequency, according to the sitemap protocol.
  36. * queryset -- pass in a query set to restrict the Pages to include
  37. in the site map.
  38. * filter -- pass in a callable that transforms a queryset to filter
  39. out the pages you want to include in the site map.
  40. * extended_navigation -- if set to True, adds pages from any navigation
  41. extensions. If using PagePretender, make sure to include title, url,
  42. level, in_navigation and optionally modification_date.
  43. """
  44. super(PageSitemap, self).__init__(*args, **kwargs)
  45. self.depth_cutoff = max_depth
  46. self.navigation_only = navigation_only
  47. self.changefreq = changefreq
  48. self.filter = filter
  49. self.extended_navigation = extended_navigation
  50. if queryset is not None:
  51. self.queryset = queryset
  52. else:
  53. Page = apps.get_model(*page_model.split("."))
  54. self.queryset = Page.objects.active()
  55. def items(self):
  56. """
  57. Consider all pages that are active and that are not a redirect
  58. """
  59. base_qs = self.queryset
  60. if callable(base_qs):
  61. base_qs = base_qs()
  62. self.max_depth = base_qs.aggregate(Max("level"))["level__max"] or 0
  63. if self.depth_cutoff > 0:
  64. self.max_depth = min(self.depth_cutoff, self.max_depth)
  65. qs = base_qs.filter(redirect_to="")
  66. if self.filter:
  67. qs = self.filter(qs)
  68. if self.navigation_only:
  69. qs = qs.filter(in_navigation=True)
  70. if self.depth_cutoff > 0:
  71. qs = qs.filter(level__lte=self.max_depth - 1)
  72. pages = [p for p in qs if p.is_active()]
  73. if self.extended_navigation:
  74. for idx, page in enumerate(pages):
  75. if self.depth_cutoff > 0 and page.level == self.max_depth:
  76. continue
  77. if getattr(page, "navigation_extension", None):
  78. cnt = 0
  79. for p in page.extended_navigation():
  80. depth_too_deep = (
  81. self.depth_cutoff > 0 and p.level > self.depth_cutoff
  82. )
  83. not_in_nav = self.navigation_only and not p.in_navigation
  84. if depth_too_deep or not_in_nav:
  85. continue
  86. cnt += 1
  87. pages.insert(idx + cnt, p)
  88. if p.level > self.max_depth:
  89. self.max_depth = p.level
  90. self.per_level = 1.0 / (self.max_depth + 1.0)
  91. return pages
  92. def lastmod(self, obj):
  93. return getattr(obj, "modification_date", None)
  94. # the priority is computed of the depth in the tree of a page
  95. # may we should make an extension to give control to the user for priority
  96. def priority(self, obj):
  97. """
  98. The priority is staggered according to the depth of the page in
  99. the site. Top level get highest priority, then each level is decreased
  100. by per_level.
  101. """
  102. if getattr(obj, "override_url", "") == "/":
  103. prio = 1.0
  104. else:
  105. prio = 1.0 - (obj.level + 1) * self.per_level
  106. # If the page is in_navigation, then it's more important, so boost
  107. # its importance
  108. if obj.in_navigation:
  109. prio += 1.2 * self.per_level
  110. return "%0.2g" % min(1.0, prio)
  111. # ------------------------------------------------------------------------