Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting parent and child page types with Python using Wagtail CMS

I am setting up a Wagtail website.

There will be an Event Index page with Events as child pages.

Each event page could also have child pages, if it is part of a event series.

The main event will show the child events as a series of links on the page. The child events also need to display the parent event and also its own siblings.

In models.py I have an Event class. So far I am detecting children, siblings, parents like this:

@property
def childpages(self):
    event_children = Event.objects.live().descendant_of(self)
    return event_children

@property
def parentpage(self):
    event_parent = self.get_parent()
    return event_parent

@property
def siblingpages(self):
    event_siblings = Event.objects.live().sibling_of(self, inclusive=False)
    return event_siblings

Is there a way of finding out what the parent page type is? If it is the event index I wouldn't want to display it on the event page. I also wouldn't want the main event pages to show siblings.

I've tried various things with not_child_of(somepage) but not quite sure how to use this. What does 'somepage' reference? A class, a variable? I'm used to Javascript and pretty new to Python.

like image 351
juliaranne Avatar asked Jan 30 '23 01:01

juliaranne


1 Answers

Here's how I'd write it:

@property
def parent_event(self):
    parent_page = self.get_parent()
    if parent_page.specific_class == Event:
        return parent_page.specific  # or just `return parent_page` if you don't need the extra detail from that page
    else:
        return None

@property
def sibling_events(self):
    parent_page = self.get_parent()
    if parent_page.specific_class == Event:
        return Event.objects.live().sibling_of(self, inclusive=False)
    else:
        # this is not a child event, so don't return siblings
        return Event.objects.none()

In Python, the standard way of checking whether an object is an instance of a given class (i.e. in Wagtail terms, whether a page is of a particular type) is isinstance(parent_page, Event).

However, with Wagtail there's an extra complication - when you traverse up and down the page tree using methods like get_parent and get_children, there's no way for it to know in advance which page type it's going to get back - so, for performance reasons, it will return a "minimal" object of type Page which includes just the properties like title that are common to all pages. So, self.get_parent().title would work, but self.get_parent().start_date wouldn't. To turn that into a "real" object of the proper type, you'd access the property specific, which will do an extra database request behind the scenes to fill in the missing detail.

(Note that this doesn't apply when you run a query that explicitly asks for a specific type of page: with a query like Event.objects.sibling_of(self), we know we'll be getting Event pages back, so we don't need to call specific on the results.)

So, if isinstance(parent_page, Event): wouldn't work - it'll always be false, because at that point parent_page is a basic Page object (regardless of whether the page is really an Event or an EventIndex).

if isinstance(parent_page.specific, Event): would work, but it's a little bit inefficient, because in the case that parent_page is the event index page, you're firing off an extra database request that you don't really need. A better alternative is to use parent_page.specific_class, which tells you the specific type of the page without firing off that extra database request.

like image 74
gasman Avatar answered Feb 02 '23 09:02

gasman