This is part 2, coming from the previous article/video. In this lesson we'll be using a SnippetChooserPanel to select Blog Authors (a snippet we registered last episode). We'll also add in an Orderable to our Blog Detail Page so we can select between 1 and 4 Blog Authors.
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:
Orderable
with a ForeignKey
to the Django ModelSnippetChooserPanel
that links to the ForeignKey
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.
# 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 %}