Skip to content

Commit 6350027

Browse files
authored
#345 Implement crumbs (#346)
* #345 Simplify breadcrumbs logic * #345 Rm model.Page.get_index method * #345 Implement breadcrumbs functions * #345 Rm redundant "select_related" field * #345 Minor logic fixes * #345 Review#1 fix. Create two public methods instead of one with configuration
1 parent 202424c commit 6350027

File tree

6 files changed

+63
-132
lines changed

6 files changed

+63
-132
lines changed

pages/logic/page.py

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,25 @@ def __init__(self, model: models.Page):
99
# But "model" is Django standard.
1010
self.model = model
1111

12-
def breadcrumbs(self) -> 'Breadcrumbs':
13-
pass
12+
def __str__(self):
13+
return f'<logic.Page: {str(self.model)}>'
14+
15+
def __repr__(self):
16+
return f'<logic.Page: {str(self.model)}>'
1417

1518
@property
1619
def siblings(self) -> models.PageQuerySet:
17-
return self.model.parent.children.exclude(id=self.model.id)
18-
19-
20-
# @todo #343:60m Implement Breadcrumbs class.
21-
# Use it instead of monolithic logic at the `breadcrumbs_with_siblings`.
22-
# Create Breadcrumb class or named tuple to specify crumb data structure.
23-
class Breadcrumbs:
24-
def __init__(self, page_model: models.Page):
25-
self.model = page_model
26-
27-
def query(self, include_self: bool) -> models.PageQuerySet:
28-
return (
29-
self.model
30-
.get_ancestors(include_self)
31-
.select_related(self.model.related_model_name)
32-
.active()
33-
)
34-
35-
def list(self, include_self=False) -> typing.List[typing.Tuple[str, str]]:
36-
"""Breadcrumbs list consists of current page ancestors."""
37-
return [
38-
(crumb.display_menu_title, crumb.url)
39-
for crumb in self.query(include_self).iterator()
40-
]
41-
42-
def list_with_self(self) -> list:
43-
return self.list(include_self=True)
20+
return self.model.parent.children.active().exclude(id=self.model.id)
21+
22+
@property
23+
def breadcrumbs(self) -> 'Pages':
24+
return Pages(self.model.get_ancestors(include_self=True).active())
25+
26+
27+
class Pages:
28+
def __init__(self, models: typing.Iterable[models.Page]):
29+
self.models = models
4430

31+
def __iter__(self):
32+
for model in self.models:
33+
yield Page(model)

pages/models.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,6 @@ class Meta:
137137
verbose_name=_('page template')
138138
)
139139

140-
@classmethod
141-
def get_index(cls):
142-
return Page.objects.filter(type=cls.CUSTOM_TYPE, slug=cls.INDEX_PAGE_SLUG).first()
143-
144140
@property
145141
def url(self):
146142
return self.get_absolute_url()
Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
{% load pages_extras %}
22

33
<div class="breadcrumbs-wrapper" itemscope itemtype="https://schema.org/BreadcrumbList">
4-
{% for name, url in crumbs_list %}
5-
{% if url %}
6-
<span class="breadcrumbs-item" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
7-
<a href="{{ base_url }}{{ url }}" itemprop="item" class="breadcrumbs-link">
8-
<span itemprop="name">{{ name }}</span>
9-
</a>
10-
<meta itemprop="position" content="{{ forloop.counter }}">
11-
{% if not forloop.last %}
12-
<span class="breadcrumbs-separator">{{ separator }}</span>
13-
{% endif %}
14-
</span>
4+
{% for logic_page in breadcrumbs %}
5+
<span class="breadcrumbs-item" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
6+
{% if not forloop.last %}
7+
<a href="{{ logic_page.model.url }}" itemscope itemtype="http://schema.org/Thing" itemprop="item"
8+
class="breadcrumbs-link">
9+
<span itemprop="name">{{ logic_page.model.display_menu_title }}</span>
10+
</a>
1511
{% else %}
16-
<span>{{ name }}</span>
12+
<span itemprop="name">{{ logic_page.model.display_menu_title }}</span>
1713
{% endif %}
14+
15+
{% if show_siblings and logic_page.siblings %}
16+
<ul class="breadcrumbs-siblings-links list-white">
17+
{% for page in logic_page.siblings %}
18+
<li>
19+
<a href="{{ page.url }}" class="list-white-link">
20+
{{ page.display_menu_title }}
21+
</a>
22+
</li>
23+
{% endfor %}
24+
</ul>
25+
{% endif %}
26+
27+
<meta itemprop="position" content="{{ forloop.counter }}">
28+
{% if not forloop.last %}
29+
<span class="breadcrumbs-separator">{{ separator }}</span>
30+
{% endif %}
31+
</span>
1832
{% endfor %}
1933
</div>

pages/templates/pages/breadcrumbs_with_siblings.html

Lines changed: 0 additions & 33 deletions
This file was deleted.

pages/templatetags/pages_extras.py

Lines changed: 17 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,65 +8,30 @@
88
register = template.Library()
99

1010

11-
@register.inclusion_tag('pages/breadcrumbs.html')
12-
def breadcrumbs(page: Page, separator='', base_url=''):
13-
index = page.get_index()
14-
15-
crumbs_list = (
16-
(index.display_menu_title, index.url) if index else ('Main', '/'),
17-
*page.get_ancestors_fields('display_menu_title', 'url', include_self=False),
18-
(page.display_menu_title, '')
19-
)
20-
11+
def _base_breadcrumbs(page: Page, separator='', *, show_siblings=False):
2112
return {
22-
'crumbs_list': crumbs_list,
13+
'breadcrumbs': [
14+
# @todo #345:60m Refold catalog pages in DB.
15+
# In both fixtures and local DB.
16+
# Implement this pages structure:
17+
# - each(category_roots).parent == CustomPage.get('catalog')
18+
# - CustomPage.get('catalog').parent == CustomPage.get('index')
19+
logic.Page(model=CustomPage.objects.get(slug='')), # index page
20+
*list(logic.Page(model=page).breadcrumbs)
21+
],
2322
'separator': separator,
24-
'base_url': base_url,
23+
'show_siblings': show_siblings,
2524
}
2625

2726

28-
@register.inclusion_tag('pages/breadcrumbs_with_siblings.html')
29-
def breadcrumbs_with_siblings(
30-
page: Page, separator='', base_url='', include_self=False
31-
):
32-
def get_ancestors_crumbs() -> list:
33-
ancestors_query = (
34-
page
35-
.get_ancestors(include_self)
36-
.select_related(page.related_model_name)
37-
.active()
38-
)
39-
40-
if not ancestors_query.exists():
41-
return []
42-
43-
catalog, *ancestors = ancestors_query
44-
45-
return [
46-
(catalog.display_menu_title, catalog.url, []),
47-
*[
48-
(
49-
crumb.display_menu_title,
50-
crumb.url,
51-
list(logic.Page(page).siblings)
52-
) for crumb in ancestors
53-
],
54-
]
55-
56-
index = page.get_index()
27+
@register.inclusion_tag('pages/breadcrumbs.html')
28+
def breadcrumbs(page: Page, separator=''):
29+
return _base_breadcrumbs(page, separator, show_siblings=False)
5730

58-
crumbs_list = [
59-
(index.display_menu_title, index.url, []) if index else ('Main', '/', []),
60-
*get_ancestors_crumbs(),
61-
(page.display_menu_title, '', logic.Page(page).siblings)
62-
]
6331

64-
return {
65-
'index_slug': index.url if index else '/',
66-
'crumbs_list': crumbs_list,
67-
'separator': separator,
68-
'base_url': base_url,
69-
}
32+
@register.inclusion_tag('pages/breadcrumbs.html')
33+
def breadcrumbs_with_siblings(page: Page, separator=''):
34+
return _base_breadcrumbs(page, separator, show_siblings=True)
7035

7136

7237
@register.inclusion_tag('pages/accordion.html')

tests/catalog/test_views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
"""
22
Defines tests for views in Catalog app
33
"""
4-
from django.test import TestCase
54
from django.core.urlresolvers import reverse
5+
from django.test import TestCase
66

77
from pages.models import CustomPage
8-
98
from tests.catalog.models import MockCategory, MockProduct
109

1110

@@ -87,6 +86,7 @@ def test_product_page(self):
8786
response = self.client.get(self.test_product.url)
8887
self.assertEqual(response.status_code, 200)
8988

89+
# @todo #345:30m Test crumbs siblings.
9090
def test_category_crumbs(self):
9191
"""Category should have valid crumbs"""
9292
page = self.test_last.page

0 commit comments

Comments
 (0)