Commit 7c6af7be by Bridger Maxwell

Added caching of ancestors for urlpath to reduce sql queries.

parent df4fd062
...@@ -15,6 +15,8 @@ from wiki.core.exceptions import NoRootURL, MultipleRootURLs ...@@ -15,6 +15,8 @@ from wiki.core.exceptions import NoRootURL, MultipleRootURLs
from wiki.models.article import ArticleRevision, ArticleForObject, Article from wiki.models.article import ArticleRevision, ArticleForObject, Article
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
URLPATH_PREFECTED_PROPERTIES = ["parent", "article__current_revision"]
class URLPath(MPTTModel): class URLPath(MPTTModel):
""" """
Strategy: Very few fields go here, as most has to be managed through an Strategy: Very few fields go here, as most has to be managed through an
...@@ -36,16 +38,29 @@ class URLPath(MPTTModel): ...@@ -36,16 +38,29 @@ class URLPath(MPTTModel):
parent = TreeForeignKey('self', null=True, blank=True, related_name='children') parent = TreeForeignKey('self', null=True, blank=True, related_name='children')
@property @property
def cached_ancestors(self):
if not hasattr(self, "_cached_ancestors"):
self._cached_ancestors = list(self.get_ancestors().select_related(*URLPATH_PREFECTED_PROPERTIES) )
return self._cached_ancestors
@cached_ancestors.setter
def cached_ancestors(self, ancestors):
self._cached_ancestors = ancestors
@property
def path(self): def path(self):
if not self.parent: return "" if not self.parent: return ""
if not hasattr(self, '_cachedpath'):
self._cachedpath = "/".join([obj.slug if obj.slug else "" for obj in self.get_ancestors(include_self=True).exclude(parent=None)]) + "/" ancestors = filter(lambda ancestor: ancestor.parent is not None, self.cached_ancestors)
return self._cachedpath slugs = [obj.slug if obj.slug else "" for obj in ancestors + [self] ]
return "/".join(slugs) + "/"
@classmethod @classmethod
def root(cls): def root(cls):
site = Site.objects.get_current() site = Site.objects.get_current()
root_nodes = list(cls.objects.root_nodes().filter(site=site)) root_nodes = list(cls.objects.root_nodes().filter(site=site).select_related(*URLPATH_PREFECTED_PROPERTIES))
# We fetch the nodes as a list and use len(), not count() because we need # We fetch the nodes as a list and use len(), not count() because we need
# to get the result out anyway. This only takes one sql query # to get the result out anyway. This only takes one sql query
no_paths = len(root_nodes) no_paths = len(root_nodes)
...@@ -108,9 +123,13 @@ class URLPath(MPTTModel): ...@@ -108,9 +123,13 @@ class URLPath(MPTTModel):
parent = cls.root() parent = cls.root()
for slug in slugs: for slug in slugs:
if settings.URL_CASE_SENSITIVE: if settings.URL_CASE_SENSITIVE:
parent = parent.get_children().get(slug=slug) child = parent.get_children().select_related(*URLPATH_PREFECTED_PROPERTIES).get(slug=slug)
child.cached_ancestors = parent.cached_ancestors + [parent]
parent = child
else: else:
parent = parent.get_children().get(slug__iexact=slug) child = parent.get_children().select_related(*URLPATH_PREFECTED_PROPERTIES).get(slug__iexact=slug)
child.cached_ancestors = parent.cached_ancestors + [parent]
parent = child
level += 1 level += 1
return parent return parent
......
{% load i18n %}{% load url from future %} {% load i18n %}{% load url from future %}
{% if urlpath %} {% if urlpath %}
<ul class="breadcrumb pull-left" class=""> <ul class="breadcrumb pull-left" class="">
{% for ancestor in urlpath.get_ancestors.all %} {% for ancestor in urlpath.cached_ancestors %}
<span class="divider">/</span> <span class="divider">/</span>
<li><a href="{% url 'wiki:get' path=ancestor.path %}">{{ ancestor.article.current_revision.title }}</a></li> <li><a href="{% url 'wiki:get' path=ancestor.path %}">{{ ancestor.article.current_revision.title }}</a></li>
{% endfor %} {% endfor %}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment