I'm creating a page with wagtail where I need to know the previous and next sibling of the current page:
In my portrait page model, I tried to define two methods to find the correct urls, but I'm missing a crucial part. To get the first sibling, I can just do the following:
class PortraitPage(Page):
...
def first_portrait(self):
return self.get_siblings().live().first().url
There is the first()
and last()
method, but there doesn't seem to be a next()
or previous()
method to get the direct neighbours (in the order that they are arranged in the wagtail admin).
Is there any way to achieve this?
Django-Treebeard provides get_next_sibling
and get_prev_sibling
which will return your direct siblings in the tree, but these are not necessarily your next published sibling. To request those you can use:
prev = page.get_prev_siblings().live().first()
next = page.get_next_siblings().live().first()
Which can obviously also be chained with any other queryset operations.
After going through the debugger for a while, I found out that wagtail already has two methods: get_prev_sibling()
and get_next_sibling()
.
So the methods could look like this (accounting for the first page in the previous method and the last item in the next method):
def prev_portrait(self):
if self.get_prev_sibling():
return self.get_prev_sibling().url
else:
return self.get_siblings().last().url
def next_portrait(self):
if self.get_next_sibling():
return self.get_next_sibling().url
else:
return self.get_siblings().first().url
Here's a version handling non-published
siblings.
def next_portrait(self):
next_sibling = self.get_next_sibling()
if next_sibling and next_sibling.live:
return next_sibling.url
else:
next_published_siblings = self.get_next_siblings(
inclusive=False
).live()
if len(next_published_siblings):
return next_published_siblings[0].url
return self.get_siblings().live().first().url
def prev_portrait(self):
previous_sibling = self.get_prev_sibling()
if previous_sibling and previous_sibling.live:
return previous_sibling.url
else:
previous_published_siblings = self.get_prev_siblings(
inclusive=False
).live()
if len(previous_published_siblings):
return previous_published_siblings[0].url
return self.get_siblings().live().last().url
You can define properties in your class that inherits from Page
Siblings
If you want the siblings of an instance of Page
, you can use the following (based on Danielle Madeley's answer):
class PortraitPage(Page):
# ...
@property
def next_sibling(self):
return self.get_next_siblings().live().first()
@property
def prev_sibling(self):
return self.get_prev_siblings().live().first()
Siblings of the same class
If you want the the siblings of PortraitPage
, specify self.__class__
in the type
method as follows:
class PortraitPage(Page):
# ...
@property
def next_sibling(self):
return self.get_next_siblings().type(self.__class__).live().first()
@property
def prev_sibling(self):
return self.get_prev_siblings().type(self.__class__).live().first()
Template
If you want to use them in a template, after defining the properties, do the following:
{# This is a template #}
Previous Sibling: {{ page.next_sibling }}
Next Sibling: {{ page.prev_sibling }}