Kim Kim - 3 months ago 52
Python Question

Looping through Wagtail Streamfield Items

I'm trying to create an index page containing links to multiple photo galleries in Wagtail. The GalleryIndexPage model looks like this:

class GalleryIndexPage(Page):
subpage_types = ['home.GalleryPage']

gallery_thumb = StreamField ([
('cover_photo', ImageChooserBlock()),
('title', blocks.CharBlock()),
('link', URLBlock()),
])

content_panels = Page.content_panels + [
StreamFieldPanel('gallery_thumb'),
]


I'm having difficulty rendering it into the template with a "gallery-item" class around each set of data. I realize that it is currently looping through and adding a class of "gallery-item" to each block inside the Streamfield, rather than around the whole Streamfield set. Here is my template code:

<div class="photo-gallery">
{% for block in self.gallery_thumb %}
<div class="gallery-item">
{% if block.block_type == 'cover_photo' %}
<div class="thumb">
{% image block.value fill-200x150 %}
</div>
{% endif %}
{% if block.block_type == 'title' %}
<div class="title">
<p>{{ block.value }}</p>
</div>
{% endif %}
{% if block.block_type == 'link' %}
<div class="link">
<a href="{{ block.value }}">View Gallery</a>
</div>
{% endif %}
</div>
{% endfor %}




Is there another way I should approach this?

EDIT:
I have added a StructBlock within my StreamField like so:

class GalleryIndexPage(Page):
subpage_types = ['home.GalleryPage']

gallery = StreamField ([
('gallery_item', blocks.StructBlock([
('cover_photo', ImageChooserBlock()),
('title', blocks.CharBlock()),
('link', URLBlock()),
], icon='user'))
])

content_panels = Page.content_panels + [
StreamFieldPanel('gallery'),
]


I'm not sure how to access these values in my template? Here is what I have so far:

<div class="photo-gallery">
{% for block in self.gallery %}
<div class="gallery-item">
<div class="thumb">
{% image self.cover_photo width-200 %}
</div>
<div class="title">
<p>{{ self.title }}</p>
</div>
<div class="link">
<a href="{{ self.link }}">>> View Gallery</a>
</div>
</div>
{% endfor %}
</div>

Answer

It seems like what you want is a single gallery_item block that consists of an image, title, and link. You can do this by creating your own block type out of simpler block types. See http://docs.wagtail.io/en/v1.5.3/topics/streamfield.html#structural-block-types

You could do something like this:

('gallery_item', blocks.StructBlock([
    ('title', blocks.CharBlock()),
    ('link', blocks.URLBlock()),
    ('image', ImageChooserBlock()),
], icon='xyz'))

You can also create this as a Python class, which is what I usually prefer to do, this is covered in the last part of the section I linked to above.

You can create your own template for this block.

If you have trouble getting this working, please update the question with what you tried.

Comments