From bb2ad79f7f4d48964a2a8c0ce51266ae7a5c4ab9 Mon Sep 17 00:00:00 2001 From: duker33 Date: Wed, 18 Sep 2019 15:06:59 +0300 Subject: [PATCH] #343 Drop redundant logic from siblings fetching. High level arch for breadcrumbs --- pages/logic/__init__.py | 3 +++ pages/logic/page.py | 43 ++++++++++++++++++++++++++++++ pages/templatetags/pages_extras.py | 30 +++++---------------- tests/pages/logic/__init__.py | 0 tests/pages/logic/test_page.py | 21 +++++++++++++++ 5 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 pages/logic/__init__.py create mode 100644 pages/logic/page.py create mode 100644 tests/pages/logic/__init__.py create mode 100644 tests/pages/logic/test_page.py diff --git a/pages/logic/__init__.py b/pages/logic/__init__.py new file mode 100644 index 0000000..9b5532a --- /dev/null +++ b/pages/logic/__init__.py @@ -0,0 +1,3 @@ +from .page import * + +__all__ = ['page'] diff --git a/pages/logic/page.py b/pages/logic/page.py new file mode 100644 index 0000000..c3fe634 --- /dev/null +++ b/pages/logic/page.py @@ -0,0 +1,43 @@ +import typing + +from pages import models + + +class Page: + def __init__(self, model: models.Page): + # "record" is much more good field name, i suppose. + # But "model" is Django standard. + self.model = model + + def breadcrumbs(self) -> 'Breadcrumbs': + pass + + @property + def siblings(self) -> models.PageQuerySet: + return self.model.parent.children.exclude(id=self.model.id) + + +# @todo #343:60m Implement Breadcrumbs class. +# Use it instead of monolithic logic at the `breadcrumbs_with_siblings`. +# Create Breadcrumb class or named tuple to specify crumb data structure. +class Breadcrumbs: + def __init__(self, page_model: models.Page): + self.model = page_model + + def query(self, include_self: bool) -> models.PageQuerySet: + return ( + self.model + .get_ancestors(include_self) + .select_related(self.model.related_model_name) + .active() + ) + + def list(self, include_self=False) -> typing.List[typing.Tuple[str, str]]: + """Breadcrumbs list consists of current page ancestors.""" + return [ + (crumb.display_menu_title, crumb.url) + for crumb in self.query(include_self).iterator() + ] + + def list_with_self(self) -> list: + return self.list(include_self=True) diff --git a/pages/templatetags/pages_extras.py b/pages/templatetags/pages_extras.py index 5652467..356569f 100644 --- a/pages/templatetags/pages_extras.py +++ b/pages/templatetags/pages_extras.py @@ -2,6 +2,7 @@ from django.conf import settings from django.core.urlresolvers import reverse +from pages import logic from pages.models import CustomPage, FlatPage, Page register = template.Library() @@ -28,21 +29,6 @@ def breadcrumbs(page: Page, separator='', base_url=''): def breadcrumbs_with_siblings( page: Page, separator='', base_url='', include_self=False ): - def get_siblings(page): - def is_node(page): - return hasattr(page.model, 'children') - - if not is_node(page): - return [] - - siblings = page.get_siblings().select_related(page.related_model_name) - - return [ - sibling - for sibling in siblings - if is_node(sibling) - ] - def get_ancestors_crumbs() -> list: ancestors_query = ( page @@ -56,16 +42,14 @@ def get_ancestors_crumbs() -> list: catalog, *ancestors = ancestors_query - siblings = [ - get_siblings(ancestor) - for ancestor in ancestors - ] - return [ (catalog.display_menu_title, catalog.url, []), *[ - (crumb.display_menu_title, crumb.url, crumb_links) - for crumb, crumb_links in zip(ancestors, siblings) + ( + crumb.display_menu_title, + crumb.url, + list(logic.Page(page).siblings) + ) for crumb in ancestors ], ] @@ -74,7 +58,7 @@ def get_ancestors_crumbs() -> list: crumbs_list = [ (index.display_menu_title, index.url, []) if index else ('Main', '/', []), *get_ancestors_crumbs(), - (page.display_menu_title, '', get_siblings(page)) + (page.display_menu_title, '', logic.Page(page).siblings) ] return { diff --git a/tests/pages/logic/__init__.py b/tests/pages/logic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/pages/logic/test_page.py b/tests/pages/logic/test_page.py new file mode 100644 index 0000000..9306dc3 --- /dev/null +++ b/tests/pages/logic/test_page.py @@ -0,0 +1,21 @@ +from django.test import TestCase + +from pages import models + + +class PageTests(TestCase): + fixtures = ['catalog.json'] + + @property + def page(self): + return ( + models.Page.objects + .active() + .filter(type=models.Page.MODEL_TYPE) + .exclude(parent=None) + .exclude(parent=models.CustomPage.objects.get(slug='catalog')) + .first() + ) + + def test_breadcrumbs(self): + ...