general: create page hierarchy beforehand (#24238)

This commit is contained in:
Frédéric Péters 2018-06-02 15:29:16 +02:00
parent 9e6adee4f9
commit 35d9a1bbba
4 changed files with 49 additions and 24 deletions

View File

@ -95,8 +95,8 @@ def get_page_dict(request, page, manifest):
if page_dict.get('external') and icon_cells[0].embed_page:
page_dict['external'] = False
if hasattr(page, '_children') and page._children:
children = page._children
if page.slug == 'index' and page.parent_id is None: # home
children = page.get_siblings()[1:]
else:
children = page.get_children()
@ -143,18 +143,11 @@ def generate_manifest(request):
# - the application pages are created from the homepage siblings and their
# children
# - the application menu is created from direct children of the homepage
children = []
homepage = None
for page in level0_pages:
if page.slug == 'index':
homepage = page
else:
children.append(page)
if not homepage:
try:
homepage = Page.objects.get(slug='index', parent_id=None)
except Page.DoesNotExist:
raise GenerationError(_('The homepage needs to be created first.'))
homepage._children = children
manifest.update(get_page_dict(request, homepage, manifest))
# footer

View File

@ -145,7 +145,6 @@ class Page(models.Model):
related_cells = JSONField(blank=True)
_level = None
_children = None
class Meta:
ordering = ['order']
@ -185,7 +184,7 @@ class Page(models.Model):
pages = [self]
page = self
while page.parent_id:
page = page.parent
page = page._parent if hasattr(page, '_parent') else page.parent
pages.append(page)
return list(reversed(pages))
@ -202,7 +201,7 @@ class Page(models.Model):
parts = [self]
page = self
while page.parent_id:
page = page.parent
page = page._parent if hasattr(page, '_parent') else page.parent
parts.append(page)
parts.reverse()
try:
@ -211,12 +210,19 @@ class Page(models.Model):
return None
def get_siblings(self):
return Page.objects.filter(parent=self.parent)
if hasattr(self, '_parent'):
if self._parent:
return self._parent._children
return Page.objects.filter(parent_id=self.parent_id)
def get_children(self):
if hasattr(self, '_children'):
return self._children
return Page.objects.filter(parent_id=self.id)
def has_children(self):
if hasattr(self, '_children'):
return bool(self._children)
return Page.objects.filter(parent_id=self.id).exists()
def get_template_display_name(self):
@ -282,7 +288,6 @@ class Page(models.Model):
parenting[page.parent_id].append(page)
def fill_list(object_sublist, level=0, parent=None):
for page in object_sublist:
page._children = parenting.get(page.id)
if page.parent == parent:
page.level = level
reordered.append(page)
@ -291,6 +296,23 @@ class Page(models.Model):
fill_list(object_list)
return reordered
@staticmethod
@utils.cache_during_request
def get_with_hierarchy_attributes():
pages = Page.objects.all()
pages_by_id = {}
for page in pages:
pages_by_id[page.id] = page
page._parent = None
page._children = []
for page in pages:
page._parent = pages_by_id[page.parent_id] if page.parent_id else None
if page._parent:
page._parent._children.append(page)
for page in pages:
page._children.sort(key=lambda x: x.order)
return pages_by_id
def visibility(self):
if self.public:
return _('Public')

View File

@ -16,6 +16,9 @@
from django.template.loader import get_template
from combo.data.models import Page
def render_menu(context, level=0, root_page=None, depth=1):
context['root_page'] = root_page
if root_page:
@ -25,17 +28,23 @@ def render_menu(context, level=0, root_page=None, depth=1):
return template.render(context)
def get_menu_context(context, level=0, current_page=None, depth=1):
if 'hierarchical_pages_by_id' not in context:
context['hierarchical_pages_by_id'] = Page.get_with_hierarchy_attributes()
pages_by_id = context['hierarchical_pages_by_id']
context['depth'] = depth
if current_page is None:
current_page = context['page']
current_page = pages_by_id.get(context['page'].id, context['page'])
else:
current_page = pages_by_id.get(current_page.id, current_page)
if 'root_page' in context:
root_page = pages_by_id[context['root_page'].id] if context.get('root_page') else None
# if the menu is anchored at a specific root page, we make sure the
# current page is in the right path, otherwise we fall back to using
# the root page as base.
ariane = current_page.get_parents_and_self()
if not context.get('root_page') in ariane:
page_of_level = context['root_page']
if not root_page in ariane:
page_of_level = root_page
else:
page_of_level = current_page.get_page_of_level(level)
else:
@ -51,7 +60,7 @@ def get_menu_context(context, level=0, current_page=None, depth=1):
context['menuitems'] = []
return context
else:
if page_of_level is context.get('root_page'):
if page_of_level == context.get('root_page'):
elements = page_of_level.get_children()
else:
elements = page_of_level.get_siblings()

View File

@ -103,20 +103,21 @@ def test_page_footer_acquisition(app):
page5.save()
ParentContentCell(page=page5, placeholder='footer', order=0).save()
# check growth in SQL queries is limited to an additional page lookup
# check growth in SQL queries is limited
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/second/third/', status=200)
assert resp.body.count('BARFOO') == 1
assert resp.body.count('BAR2FOO') == 1
queries_count_third = len(ctx.captured_queries)
assert queries_count_third == queries_count_second + 1
assert queries_count_third == queries_count_second
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/second/third/fourth/', status=200)
assert resp.body.count('BARFOO') == 1
assert resp.body.count('BAR2FOO') == 1
queries_count_fourth = len(ctx.captured_queries)
assert queries_count_fourth == queries_count_second + 2
# +1 for get_parents_and_self()
assert queries_count_fourth == queries_count_second + 1
# check footer doesn't get duplicated in real index children
page6 = Page(title='Sixth', slug='sixth', template_name='standard', parent=page_index)