Трясогузка: получить предыдущего или следующего брата или сестру

Я создаю страницу с трясогузкой, где мне нужно знать предыдущий и следующий брат текущей страницы:

В моей модели портретной страницы я попытался определить два метода для поиска правильных URL-адресов, но мне не хватает важной части. Чтобы получить первого брата, я могу просто сделать следующее:

class PortraitPage(Page):

    ...

    def first_portrait(self):
        return self.get_siblings().live().first().url

Есть метод first() и last(), но next() или previous() метода, чтобы получить непосредственных соседей (в том порядке, в котором они расположены в админке трясогузки), похоже, нет.

Есть ли способ добиться этого?


person nils    schedule 20.05.2015    source источник


Ответы (5)


Django-Treebeard предоставляет get_next_sibling и get_prev_sibling, которые вернут ваших прямых братьев и сестер в дереве, но это не обязательно ваш следующий опубликованный брат или сестра. Чтобы запросить их, вы можете использовать:

prev = page.get_prev_siblings().live().first()
next = page.get_next_siblings().live().first()

Который, очевидно, также может быть связан с любыми другими операциями набора запросов.

person Danielle Madeley    schedule 22.06.2016
comment
есть ли способ добиться того же результата в шаблоне Django? - person lmiguelvargasf; 31.03.2019

Покопавшись некоторое время в отладчике, я обнаружил, что у трясогузки уже есть два метода: get_prev_sibling() и get_next_sibling().

Таким образом, методы могут выглядеть так (с учетом первой страницы в предыдущем методе и последнего элемента в следующем методе):

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
person nils    schedule 20.05.2015
comment
Я предполагаю, что это происходит из модели страницы, но я не изучал ее. Я только что сделал dir(self) и просмотрел доступные методы. И это работает. Какая у вас версия трясогузки? Я работаю над v.1.0b1 - person nils; 20.05.2015
comment
@rnevius А, ну вот, это упоминается только в примечаниях к выпуску трясогузки 0.4: docs.wagtail.io/en/latest/releases/0.4.html - person nils; 20.05.2015
comment
Привет, @nils и @rnevius, методы get_prev_sibling() и get_next_sibling() взяты из Treebeard, который обрабатывает иерархию страниц Wagtail и задокументирован здесь: tabo.pe/projects/django-treebeard/docs/1.61/ P.S. @nils, если вы используете 1.0b1, вам следует проверить версию 1.0b2, которую мы выпустили сегодня: github.com/torchbox/wagtail/releases/tag/v1.0b2 - person tomd; 20.05.2015
comment
Спасибо за информацию @tomd! Я запускаю beta2, пока мы говорим ;-) - person rnevius; 20.05.2015
comment
@tomd Я только что понял, что get_next_sibling() не содержит полей, которые я определил в модели страницы (например, header_image). Есть ли способ получить к ним доступ? - person nils; 22.05.2015
comment
@nils `.специфический. даст вам то, что вы после. - person Danielle Madeley; 22.06.2016
comment
get_next_sibling() также даст вам неопубликованные страницы. Я думаю, что это причина, почему это не задокументировано. Каков правильный способ сделать это? - person Philipp S.; 03.09.2020

Вот версия, обрабатывающая non-published братьев и сестер.

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
person raphaelstolt    schedule 06.07.2016

Вы можете определить свойства в своем классе, которые наследуются от Page

Братья и сестры

Если вам нужны братья и сестры экземпляра Page, вы можете использовать следующее (на основе ответа Даниэль Мадли):

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()

Братья и сестры одного класса

Если вам нужны братья и сестры PortraitPage, укажите self.__class__ в методе type следующим образом:

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()

Шаблон

Если вы хотите использовать их в шаблоне, после определения свойств сделайте следующее:

{# This is a template #}
Previous Sibling: {{ page.next_sibling }}
Next Sibling: {{ page.prev_sibling }}
person lmiguelvargasf    schedule 31.03.2019

self.get_siblings() не работает, если вы хотите выполнить какую-либо фильтрацию на основе свойств, найденных только в подклассе, поскольку результаты PageQuerySet имеют тип Page.

У меня есть индексная страница блога, которую можно фильтровать по категориям или тегам. В конце страницы сведений о болоте есть карточки для следующего и предыдущего сообщения в блоге. Я хотел, чтобы эти предыдущие/следующие сообщения соответствовали фильтру, из которого я попал на эту страницу.

Чтобы обойти это, вам нужно запросить объекты, принадлежащие подклассу (например, BlogDetailPage), отфильтровать их, а затем получить предыдущее/следующее сообщение, используя class.objects.sibling_of(self):

def get_context(self, request, *args, **kwargs):
    context = super().get_context(request, *args, **kwargs)
    siblings = self.__class__.objects.sibling_of(self).live()
    category_filter = request.GET.get("category", None)
    tag_filter = request.GET.get("tag", None)
    if category_filter:
        siblings = siblings.filter(categories__slug__in=category_filter.split(","))
        context["filter"] = '?category=' + category_filter
    elif tag_filter:
        siblings = siblings.filter(tags__slug__in=tag_filter.split(','))
        context["filter"] = '?tag=' + tag_filter
    else:
        context["filter"] = ''
    context["next_post"] = siblings.filter(path__gt=self.path).first()
    context["previous_post"] = siblings.filter(path__lt=self.path).first()

    return context

Я использовал self.__class__.objects.sibling_of(self), так как это суперкласс с подклассами страниц блога.

person Richard Allen    schedule 13.07.2021