Dominic M.
Dominic M.

Reputation: 913

Django Wagtail Page.objects.descendant_of(inclusive=False) Error

I'm using Django 2.0 with the latest version of Wagtail CMS. I am pretty new to Wagtail and I am trying to query the children of EventIndexPage which is EventPage and have them appear on my HomePage.

I am trying to use this line of python in home app models.py below:

special_events = EventIndexPage.objects.descendant_of(inclusive=False)

But It returns:

 return getattr(self.get_queryset(), name)(*args, **kwargs)
TypeError: descendant_of() missing 1 required positional argument: 'other'

When I try putting "EventPage" in before "inclusive=false" I get a type error because its an array not an integer.

docs: http://docs.wagtail.io/en/v2.0/reference/pages/queryset_reference.html

Models.py of the home app:

from django.db import models
from event.models import EventIndexPage

from wagtail.core.models import Page
from wagtail.core.fields import RichTextField
from wagtail.admin.edit_handlers import FieldPanel


class HomePage(Page):
    body = RichTextField(blank=True)
    special_events = EventIndexPage.objects.descendant_of(inclusive=False)

    content_panels = Page.content_panels + [
        FieldPanel('body', classname="full"),
    ]

Models.py of event app

from django.db import models

from wagtail.core.models import Page
from wagtail.core.fields import RichTextField
from wagtail.admin.edit_handlers import FieldPanel
from wagtail.search import index

class EventIndexPage(Page):
    intro = RichTextField(blank=True)

    content_panels = Page.content_panels + [
        FieldPanel('intro', classname="full")
    ]


class EventPage(Page):
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)

    search_fields = Page.search_fields + [
        index.SearchField('intro'),
        index.SearchField('body'),
    ]

    content_panels = Page.content_panels + [
        FieldPanel('date'),
        FieldPanel('intro'),
        FieldPanel('body', classname="full"),
    ]

Upvotes: 3

Views: 769

Answers (1)

gasman
gasman

Reputation: 25227

Firstly, this line of code is in the wrong place - putting it immediately within class HomePage(Page): means that your query will be run once at server startup, and the results will become part of the definition of HomePage. You probably want to make it a method of HomePage instead, so that you can re-run the query on every page load:

class HomePage(Page):
    body = RichTextField(blank=True)

    def special_events(self):
        return EventIndexPage.objects.descendant_of...

Now let's look at what descendant_of is doing. EventIndexPage.objects.descendant_of(other_page) means "find all of the EventIndexPage pages which are descendants (i.e. immediate children, or grandchildren, and so on) of other_page". Since you're actually looking for EventPage pages, not EventIndexPage, you should use EventPage.objects.descendant_of.

Now, we need to supply other_page - i.e. tell it which page they need to be descendants of. You might try EventPage.objects.descendant_of(EventIndexPage), but this won't work because EventIndexPage is a page type - there could potentially be several EventIndexPages on your site, and descendant_of needs to be given one specific page instance. If you're sure you're only ever going to have one EventIndexPage on your site, you can use EventIndexPage.objects.first() to tell it "use the first EventIndexPage that you encounter", which makes the final function:

class HomePage(Page):
    body = RichTextField(blank=True)

    def special_events(self):
        event_index_page = EventIndexPage.objects.first()
        return EventPage.objects.descendant_of(event_index_page)

You can safely disregard the inclusive option here: that just determines whether a page is considered to be a descendant of itself, i.e. whether the results of descendant_of(other_page) can include other_page. In this case, the EventPage.objects.descendant_of(event_index_page) results will never include event_index_page, because event_index_page is not an EventPage.

One last suggestion, though: do you actually need to deal with the EventIndexPage at all? Presumably you're not planning to have EventPages that exist outside of the EventIndexPage, in which case it doesn't matter whether your query says "give me all EventPages that are descendants of EventIndexPage" or "give me all EventPages regardless of where they exist". If so, the function can become simply:

class HomePage(Page):
    body = RichTextField(blank=True)

    def special_events(self):
        return EventPage.objects.all()

Or, if you're applying this condition because you intend to have multiple sub-sites each with their own EventPageIndex and set of events, and only want to return events for the current sub-site, you could take advantage of the fact that the events in question are also descendants of the current homepage (i.e. self) as well as being descendants of the EventPageIndex:

class HomePage(Page):
    body = RichTextField(blank=True)

    def special_events(self):
        return EventPage.objects.descendant_of(self)

Upvotes: 5

Related Questions