-
-
Save VincentLoy/e693aa1f149a59f465a5a71b6d937b9a to your computer and use it in GitHub Desktop.
Really nice! Thanks.
This is a super helpful snippet, thank you! :)
As of Wagtail 6.1 this should get updated to populate an array inside of a view; to then use in a template.
For the routed page; this will make sure the query count will be zero.
The database should NOT be hit. AT ALL.
Storage of pages happens in routing.
Rough sketch:
class MyPage(...):
def get_context(self, ...):
context = super().get_context(...)
breadcrumbs = []
page = self
while page.get_parent() is not None:
if page.is_root():
break
# Note how we do not add self.
page = page.get_parent()
breadcrumbs.append(page)
breadcrumbs.reverse()
context["breadcrumbs"] = breadcrumbs
return context
And then in the template:
<div class="breadcrumb-content">
{% if breadcrumbs|length > 1 %}
<ul class="breadcrumb">
{% for p in breadcrumbs %}
<li><a href="{{ p.url }}">{{ p.title }}</a></li>
{% endfor %}
<li class="active">{{ self.title }}</li>
</ul>
{% endif %}
</div>
If you have articles in multiple depths (under category/subcategory/topic/...), then the following method can be useful.
- It hits DB only once, no matter the depth.
- It excludes the Root page (depth__gt=1 -> depth 0 is Root, so we only get the higher).
- Homepage is included in the list.
- It does not include the current page itself. If you want it to include, then set include_self to True.
def construct_breadcrumbs_list(page, include_self=False):
"""
Constructs a breadcrumb list for the given page, excluding the root.
Args:
page: The page object for which to construct the breadcrumb list.
include_self (bool): If True, includes the page itself in the breadcrumb list.
Returns:
list: A list of ancestor pages, excluding the root and self.
"""
# Retrieve all ancestors of the page, optionally including the page itself
ancestors = page.get_ancestors(inclusive=include_self).filter(depth__gt=1)
# Convert the queryset to a list to return the breadcrumbs
breadcrumbs = list(ancestors)
return breadcrumbs
If you have articles in multiple depths (under category/subcategory/topic/...), then the following method can be useful.
- It hits DB only once, no matter the depth.
- It excludes the Root page (depth__gt=1 -> depth 0 is Root, so we only get the higher).
- Homepage is included in the list.
- It does not include the current page itself. If you want it to include, then set include_self to True.
def construct_breadcrumbs_list(page, include_self=False): """ Constructs a breadcrumb list for the given page, excluding the root. Args: page: The page object for which to construct the breadcrumb list. include_self (bool): If True, includes the page itself in the breadcrumb list. Returns: list: A list of ancestor pages, excluding the root and self. """ # Retrieve all ancestors of the page, optionally including the page itself ancestors = page.get_ancestors(inclusive=include_self).filter(depth__gt=1) # Convert the queryset to a list to return the breadcrumbs breadcrumbs = list(ancestors) return breadcrumbs
Still does a query though... ❤️ 😉
Still does a query though... ❤️ 😉
True. However, the following method also hits one query in my case.
Edit: as I assumed, the following does not hit the db if the page is in the first depth. Otherwise, it will need to hit DB.
That's why I mentioned:
If you have articles in multiple depths (under category/subcategory/topic/...), then the following method can be useful.
breadcrumbs = [] page = self while page.get_parent() is not None: if page.is_root(): break # Note how we do not add self. page = page.get_parent() breadcrumbs.append(page) breadcrumbs.reverse()
what version of wagtail are you using?
v 6.1.
It does not hit no matter the depth of page in your case? So if we assume there is such tree: FirstPage > SecondPage > SecondPage, and you try to make breadcrumb in the ThirdPage, it is still 0?
Sorry about confusion, it actually hits one time no matter the depth in my case. I am not sure what may cause such difference. It has to get "parent" data from somewhere, either it has to be prefetched already and cached or it has to be requested.
How it would else be possible not to hit DB using get_ancestors()?
what version of wagtail are you using?
v 6.1.It does not hit no matter the depth of page in your case? So if we assume there is such tree: FirstPage > SecondPage > SecondPage, and you try to make breadcrumb in the ThirdPage, it is still 0? In my case, in SecondPage, it does not hit, but in SecondPage it does.
Hmm - very odd. No - it really shouldn't hit the DB, no matter the depth...
Possibly I made a mistake in my PR... I'll have to revisit.
I'll submit a fix - my bad. In the future you should then have zero query breadcrumbs - I think I made a mistake not setting the cache on the specific instance of the page.
Thanks for the help! :)
[EDIT]
@ismayil-ismayilov would you mind trying this repo to see if it still queries?
https://github.com/Nigel2392/wagtail/tree/update_page_routing
can be done with pip install git+https://github.com/Nigel2392/wagtail.git@update_page_routing
Thanks for the help! :)
Glad to be helpful!
Possibly I made a mistake in my PR... I'll have to revisit.
Maybe, it is my confusion. Just to make it clear, I do not used/tested routed pages, I just implemented your method to send context in a Page. Let's say there is a Blog Index Page, and I show breadcrumb Homepage>Blog Index.
@ismayil-ismayilov To be clear, you're not going from your browser to the page? IE the page.route
method does not get invoked?
Sorry about confusion, it actually hits one time no matter the depth in my case. I am not sure what may cause such difference. It has to get > "parent" data from somewhere, either it has to be prefetched already and cached or it has to be requested.
How it would else be possible not to hit DB using get_ancestors()?
Get ancestors will for now always perform a query - it is not cached.
The parent objects however are cached upon routing to that page.
IE.
Homepage
> BlogPage
> > BlogIndexPage
You should be able to travel from BlogIndexPage
to Homepage
using get_parent
without it performing any queries (inside the serve method of BlogIndexPage
, after page.route
has been invoked by the page serve view)
Can you tell me if this is the case for you?
Unfortunately, I do not think that's a case for me. I strongly believe I caused a confusion since I may not have the same application method as you refer, sorry about it.
I used your Wagtail repo. It still hits DB.
This is my "simplified" Page class. I basically, applied your method to create a breadcrumb. Nothing more or less.
Thank you!