Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #987 from ojii/fix-978

Fixed #978 with the help of @chrisglass.
  • Loading branch information...
commit 6ef4ed66d543ef83044b7306b50a8e8b008e5a9c 2 parents 5f3c331 + 9a0684c
@chrisglass chrisglass authored
Showing with 49 additions and 13 deletions.
  1. +49 −13 cms/admin/change_list.py
View
62 cms/admin/change_list.py
@@ -8,12 +8,42 @@
from django.contrib.admin.views.main import ChangeList, ALL_VAR, IS_POPUP_VAR, \
ORDER_TYPE_VAR, ORDER_VAR, SEARCH_VAR
from django.contrib.sites.models import Site
-from mptt.templatetags import mptt_tags
-
COPY_VAR = "copy"
+
+def cache_tree_children(queryset):
+ """
+ For all items in the queryset, set the '_cached_children' attribute to a
+ list. This attribute is in turn used by the 'get_children' method on the
+ item, which would otherwise (if '_cached_children' is not set) cause a
+ database query.
+
+ The queryset MUST BE ORDERED BY 'lft', 'tree_id'! Otherwise this function
+ will raise a ValueError.
+ """
+ parents_dict = {}
+ lastleft = -1 # integrity check
+ lasttree = -1 # integrity check
+ for obj in queryset:
+ parents_dict[obj.pk] = obj
+ if obj.tree_id == lasttree and obj.lft < lastleft: # integrity check
+ raise ValueError('Objects passed in the wrong order, must be ordered by the mptt left attribute and tree id')
+ lastleft = obj.lft # integrity check
+ lasttree = obj.tree_id # integrity check
+ # set the '_cached_children' attribute
+ obj._cached_children = []
+ # get the parent of this object (if available) via parent_id
+ parent = parents_dict.get(obj.parent_id, None)
+ if parent:
+ # if there is a parent, append the current object to the _cached_children
+ # list of the parent. Since the objects are ordered by lft, tree_id
+ # the _cached_children attribute will always have been set by this
+ # function already.
+ parent._cached_children.append(obj)
+
+
class CMSChangeList(ChangeList):
'''
Renders a Changelist - In our case it looks like a tree - it's the list of
@@ -50,7 +80,6 @@ def get_query_set(self, request=None):
self.root_query_set = self.root_query_set.filter(pk__in=permissions)
self.real_queryset = True
qs = qs.filter(site=self._current_site)
- qs = qs.order_by('tree_id', 'lft')
return qs
def is_filtered(self):
@@ -118,12 +147,10 @@ def set_items(self, request):
except NoHomeFound:
home_pk = 0
- # Make the pages a tree (using MPTT awesomeness).
- # This is normally a tag filter, but it's really nice in our case too:
- # It caches children for every page in the list we pass it, so no
- # further queries are needed.
-
- mptt_tags.cache_tree_children(pages)
+ # Unfortunately we cannot use the MPTT builtin code for pre-caching
+ # the children here, because MPTT expects the tree to be 'complete'
+ # and otherwise complaints about 'invalid item order'
+ cache_tree_children(pages)
for page in pages:
@@ -177,10 +204,19 @@ def set_items(self, request):
page.ancestors_ascending = []
page.home_pk_cache = home_pk
- # childrens is the reverse accessor for the parent foreign key.
- # We want to set it so the JSTree can display it nicely in admin.
- # "childrens" is the fully cached version of children.
- page.childrens = children
+ # Because 'children' is the reverse-FK accessor for the 'parent'
+ # FK from Page->Page, we have to use wrong English here and set
+ # an attribute called 'childrens'. We are aware that this is WRONG
+ # but what should we do?
+
+ # If the queryset is filtered, do NOT set the 'childrens' attribute
+ # since *ALL* pages will be in the 'root_pages' list and therefore
+ # be displayed. (If the queryset is filtered, the result is not a
+ # tree but rather a flat list).
+ if self.is_filtered():
+ page.childrens = []
+ else:
+ page.childrens = children
# TODO: OPTIMIZE!!
titles = Title.objects.filter(page__in=ids)
Please sign in to comment.
Something went wrong with that request. Please try again.