PageRenderTime 27ms CodeModel.GetById 19ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/feincms/module/page/sitemap.py

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