I have a Wagtail site with a page of music conductors. Each conductor has a section with their name, photo and biography. The conductor details are stored inside child Orderable
instances which the parent page is displaying using an InlinePanel
.
When users search my site, I want the results to contain text coming from inside the conductor details (i.e. based on their name and full biography text in the Orderable
).
Conductors Page
class ConductorsPage(Page):
max_count = 1
template = 'home/conductors.html'
content = RichTextField(
null=True,
blank=True,
)
search_fields = Page.search_fields + [
index.SearchField('content'),
index.SearchField('conductors'),
]
content_panels = Page.content_panels + [
FieldPanel('content', classname="full"),
MultiFieldPanel(
[
InlinePanel("conductors", label="Conductor")
],
heading="Conductors",
),
]
Conductor (Orderable)`
class Conductor(Orderable):
page = ParentalKey('home.ConductorsPage', related_name='conductors')
name = models.CharField(max_length=30)
photograph = models.ForeignKey(
"wagtailimages.Image",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
biography = RichTextField(
null=True,
blank=True,
features=['bold', 'italic', 'hr', 'link'],
)
search_fields = Page.search_fields + [
index.SearchField('name'),
index.SearchField('biography'),
]
panels = [
FieldPanel("name"),
ImageChooserPanel("photograph"),
FieldPanel("biography"),
]
The above code brings results based on the parent content
field but omits text from the Orderable
(e.g, biography). I am using a Postgres database (wagtail.contrib.postgres_search.backend
).
I've seen suggestions to create a method in the parent that concatenates text from the child fields and set a SearchField
on that. But that seems like a clunky solution.
What is the recommended way of implementing this in the latest versions of Wagtail?
Thank you gasman - your comment was the solution I was looking for.
For anyone who is trying to implement this, Wagtail has a very elegant way of defining search fields for child entities: RelatedFields
The search fields are added on the parent page using RelatedFields
. See code below for an example that worked for me. Now when a user runs a search the results include text within the Conductor's biography and/or name.
class ConductorsPage(Page):
max_count = 1
template = 'home/conductors.html'
content = RichTextField(
null=True,
blank=True,
features=['bold', 'italic', 'hr', 'link', 'image'],
)
search_fields = Page.search_fields + [
index.SearchField('content'),
index.RelatedFields('conductors', [
index.SearchField('name'),
index.SearchField('biography'),
]),
]
content_panels = Page.content_panels + [
FieldPanel('content', classname="full"),
FieldPanel('search_description', classname="full"),
MultiFieldPanel(
[
InlinePanel("conductors", label="Conductor")
],
heading="Conductors",
),
]
class Conductor(Orderable):
page = ParentalKey('home.ConductorsPage', related_name='conductors')
name = models.CharField(max_length=30)
photograph = models.ForeignKey(
"wagtailimages.Image",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
biography = RichTextField(
null=True,
blank=True,
features=['bold', 'italic', 'hr', 'link'],
)
panels = [
FieldPanel("name"),
ImageChooserPanel("photograph"),
FieldPanel("biography"),
]