Using a SnippetChooserPanel to Select Multiple Blog Authors (Snippets + Orderables)
This is part 2 about registering Snippets and using them in a SnippetChooserPanel. If you didn't catch the first video, you can find it here.
In this video we take an existing Snippet and let the user select the Snippet from the Wagtail Admin. But we take this a step further and allow the user to select between one and four Blog Authors by using a Orderable (more on Orderables here).
The entire process goes like this:
- Create a Django Model
- Register the model as a Wagtail Snippet
- Create an
Orderable
with aForeignKey
to the Django Model - Create a
SnippetChooserPanel
that links to theForeignKey
- On your page add an
InlinePanel
that links to your Orderable's related_name.
That's just about all there is to it. The code can be kind of confusing if this is your first time, so please take a look at the Git Commit or the chunk of code below.
The Code
# blog.models.py
"""Blog listing and blog detail pages."""
from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.admin.edit_handlers import (
FieldPanel,
MultiFieldPanel,
InlinePanel,
)
from wagtail.snippets.edit_handlers import SnippetChooserPanel
from wagtail.core.models import Page, Orderable
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.snippets.models import register_snippet
class BlogAuthorsOrderable(Orderable):
"""This allows us to select one or more blog authors from Snippets."""
page = ParentalKey("blog.BlogDetailPage", related_name="blog_authors")
author = models.ForeignKey(
"blog.BlogAuthor",
on_delete=models.CASCADE,
)
panels = [
# Use a SnippetChooserPanel because blog.BlogAuthor is registered as a snippet
SnippetChooserPanel("author"),
]
@register_snippet
class BlogAuthor(models.Model):
"""Blog author for snippets."""
name = models.CharField(max_length=100)
website = models.URLField(blank=True, null=True)
image = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.SET_NULL,
null=True,
blank=False,
related_name="+",
)
panels = [
MultiFieldPanel(
[
FieldPanel("name"),
# Use an ImageChooserPanel because wagtailimages.Image (image property)
# is a ForeignKey to an Image
ImageChooserPanel("image"),
],
heading="Name and Image",
),
MultiFieldPanel(
[
FieldPanel("website"),
],
heading="Links"
)
]
def __str__(self):
"""String repr of this class."""
return self.name
class Meta: # noqa
verbose_name = "Blog Author"
verbose_name_plural = "Blog Authors"
class BlogDetailPage(Page):
"""Blog detail page."""
# ...
content_panels = Page.content_panels + [
# ...
MultiFieldPanel(
[
InlinePanel("blog_authors", label="Author", min_num=1, max_num=4)
],
heading="Author(s)"
),
# ...
]
{# blog_detail_page.html code snippet #}
{# Loop through all blog authors #}
{% for iter in self.blog_authors.all %}
{% image iter.author.image fill-50x50 as img %}
<div>
<img src="{{ img.url }}" class="rounded-circle" alt="{{ iter.author.name }}">
</div>
{% if iter.author.website %}
{# If there's a website, create an <a> tag
<a href="{{ iter.author.website }}">
{{ iter.author.name }}
</a>
{% else %}
{# No website; no <a> tag #}
{{ iter.author.name }}
{% endif %}
</div>
{% endfor %}
The Git Commit
Just want the raw code? No problem. Follow this link to the Git Commit to see everything that was changed.
Was this helpful to you?
Sharing is caring. Help the community by sharing this article.
Kalob Taulien
Fullstack web developer and online web dev. instructor.