jsonwagtailwagtail-streamfield

Retrieve first image from a Wagtail Streamfield for blog_index_page


Assume I am following the Your first Wagtail site tutorial, except I want to use a Streamfield, instead of separate RichTextField or BlogPageGalleryImage. For example :

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

... becomes ...

class BlogPage(Page):
    body = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('intro', blocks.RichTextBlock()),
        ('body', blocks.RichTextBlock()),
        ('image', ImageChooserBlock()),
    ], null=True, blank=True,)

How can I (or can I) pull the first image and the beginning of intro (...as I cannot restrict length) from a Streamfield for use in the blog_index_page.html template, and avoid using separate fields and BlogPageGalleryImage Class? Therefore replacing this template :

{% for post in blogpages %}
{% with post=post.specific %}
    <h2><a href="{% pageurl post %}">{{ post.title }}</a></h2>

    {% with post.main_image as main_image %}
        {% if main_image %}{% image main_image fill-160x100 %}{% endif %}
    {% endwith %}

    <p>{{ post.intro }}<p>
{% endwith %}
{% endfor %}

With something more like this :

{% for post in blogpages %}
{% with post=post.specific %}
    <h2><a href="{% pageurl post %}">{{ post.title }}</a></h2>

    {{ post.body.image.first() }}

    <p>{{ post.intro.get_words(50) }}</p>
    {{ post.body|richtext }}
{% endwith %}
{% endfor %}

Many thanks.


Solution

  • I had the same exact question 5 years later, so hopefully it helps when somebody stumbles upon it. Solved it by making a method in BlogPage class that checks if there are image blocks in the body (StreamField) and retuns the first image from the first image block.

    def first_body_image(self):
        image_blocks = [block for block in self.body if block.block_type == 'image']
        if not image_blocks:
            return None
        return image_blocks[0].value
    

    And you can use it in a template with image tags

    {% image post.specific.first_body_image fill-300x300 %}