Tutorial Summary

In this video we'll learn how to create a brand new StreamField using a StructBlock to create a Call to Action section on your page. And then we'll leverage the power of StreamFields by placing this code on a second page so we can re-use all our template and logic in two (or more) places.

# flex/models.py
"""Flexible page."""
from django.db import models

from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
from wagtail.core.fields import StreamField
from wagtail.core.models import Page

from streams import blocks


class FlexPage(Page):
    """Flexible page class."""

    template = "flex/flex_page.html"

    content = StreamField(
        [
            ("title_and_text", blocks.TitleAndTextBlock()),
            ("full_richtext", blocks.RichtextBlock()),
            ("simple_richtext", blocks.SimpleRichtextBlock()),
            ("cards", blocks.CardBlock()),
            ("cta", blocks.CTABlock()),
        ],
        null=True,
        blank=True,
    )

    subtitle = models.CharField(max_length=100, null=True, blank=True)

    content_panels = Page.content_panels + [
        FieldPanel("subtitle"),
        StreamFieldPanel("content"),
    ]

    class Meta:  # noqa
        verbose_name = "Flex Page"
        verbose_name_plural = "Flex Pages"
# home/models.py
from django.db import models

from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel, PageChooserPanel
from wagtail.core.models import Page
from wagtail.core.fields import RichTextField, StreamField
from wagtail.images.edit_handlers import ImageChooserPanel

from streams import blocks


class HomePage(Page):
    """Home page model."""

    template = "home/home_page.html"
    max_count = 1

    banner_title = models.CharField(max_length=100, blank=False, null=True)
    banner_subtitle = RichTextField(features=["bold", "italic"])
    banner_image = models.ForeignKey(
        "wagtailimages.Image",
        null=True,
        blank=False,
        on_delete=models.SET_NULL,
        related_name="+"
    )
    banner_cta = models.ForeignKey(
        "wagtailcore.Page",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+"
    )

    content = StreamField(
        [
            ("cta", blocks.CTABlock()),
        ],
        null=True,
        blank=True,
    )

    content_panels = Page.content_panels + [
        FieldPanel("banner_title"),
        FieldPanel("banner_subtitle"),
        ImageChooserPanel("banner_image"),
        PageChooserPanel("banner_cta"),
        StreamFieldPanel("content"),
    ]

    class Meta:

        verbose_name = "Home Page"
        verbose_name_plural = "Home Pages"
{# templates/home/home_page.html #}
{% extends "base.html" %}

{% load wagtailcore_tags wagtailimages_tags %}

{% block content %}

    {% image self.banner_image width-3560 as img %}

    <div class="jumbotron" style="background-image: url('{{ img.url }}'); min-height: 400px; height: 40vh; background-size: cover; background-position: center top; display: flex; flex-direction: column; justify-content: center;">
        <h1 class="display-4">{{ self.banner_title }}</h1>
        <div class="lead">{{ self.banner_subtitle|richtext }}</div>
        {% if self.banner_cta %}
            <a class="btn btn-primary btn-lg" href="#" role="button">@todo</a>
        {% endif %}
    </div>

    {% for block in page.content %}
        {% include_block block %}
    {% endfor %}
{% endblock %}
{# streams/cta_block.html #}
{% load wagtailcore_tags %}

<div class="container mb-sm-5 mt-sm-5">
    <div class="row">
        <div class="col-md-5 offset-md-1 col-sm-12">
            <h1>{{ self.title }}</h1>
            {{ self.text|richtext }}

            {% if self.button_page %}
                <a href="{{ self.button_page.url }}">{{ self.button_text }}</a>
            {% elif self.button_url %}
                <a href="{{ self.button_url }}">{{ self.button_text }}</a>
            {% endif %}
        </div>
    </div>
</div>
# streams/blocks.py
"""Streamfields live in here."""

from wagtail.images.blocks import ImageChooserBlock


class CTABlock(blocks.StructBlock):
    """A simple call to action section."""

    title = blocks.CharBlock(required=True, max_length=60)
    text = blocks.RichTextBlock(required=True, features=["bold", "italic"])
    button_page = blocks.PageChooserBlock(required=False)
    button_url = blocks.URLBlock(required=False)
    button_text = blocks.CharBlock(required=True, default='Learn More', max_length=40)

    class Meta:  # noqa
        template = "streams/cta_block.html"
        icon = "placeholder"
        label = "Call to Action"
Sign up for our newsletter

Get notified about new lessons :)


Our Sites