Get Image and intro text from wagtail page chooser

394 Views Asked by At

I am incorporating a page chooser in wagtail admin, however what I want to get is the image for each item in the streamblock for the page chooser and was wanting to know if there is a way to do this. So lets say if I have a category index page I would have the following code:

{% if page.case_study %}
                            
   {% image page.case_study.image fill-50x50-c100 class="" %}
   {{ page.case_study }}
                           
{% endif %}    

All I seem to get are the links which is fine, but I need the image from that case study page. My model is as follows:

class CategoryPage(Page):
"""
Detail view for a specific category
"""
introduction = RichTextField(
    help_text='Text to describe the page',
    blank=True)
image = models.ForeignKey(
    'wagtailimages.Image',
    null=True,
    blank=True,
    on_delete=models.SET_NULL,
    related_name='+',
    help_text='Landscape mode only; horizontal width between 1000px and 3000px.'
)
body = StreamField(
    BaseStreamBlock(), verbose_name="Page body", blank=True
)
case_study = StreamField([
    ('Cases', blocks.PageChooserBlock()),
], blank=True,
   null=True,
   verbose_name='Case Studies',
)
origin = models.ForeignKey(
    Country,
    on_delete=models.SET_NULL,
    null=True,
    blank=True,
)

category_type = models.ForeignKey(
    'categories.CategoryType',
    null=True,
    blank=True,
    on_delete=models.SET_NULL,
    related_name='+'
)

categories = ParentalManyToManyField('Category', blank=True)

content_panels = Page.content_panels + [
    FieldPanel('introduction', classname="full"),
    ImageChooserPanel('image'),
    StreamFieldPanel('body'),
    StreamFieldPanel('case_study'),
    FieldPanel('origin'),
    FieldPanel('category_type'),
]

search_fields = Page.search_fields + [
    index.SearchField('body'),
]

parent_page_types = ['CategoriesIndexPage']

Any help would be greatly appreciated

1

There are 1 best solutions below

0
On BEST ANSWER

A StreamField is a list of blocks, but when you write page.case_study.image you're trying to access it as if it's only a single item. I'd suggest you start by updating your field / block names to make this distinction clearer - case_studies is the list, and each block in it is a single case (note that conventionally block names are lower-case):

case_studies = StreamField(
    [
         ('case', blocks.PageChooserBlock()),
    ],
    blank=True,
    null=True,
    verbose_name='Case Studies',
)

In your template, you will now loop over page.case_studies. However, this will not give you the case study page objects directly - each item in the list is a 'block' object, with block_type and value properties. This is because a StreamField usually involves mixing multiple block types (rather than just the one type you've defined here) and in that situation, you need some way of finding out what block type you're working with on each iteration of the loop.

{% if page.case_studies %}
    {% for block in page.case_studies %}
         {# block.value now refers to the page object #}
    {% endfor %}
{% endif %}

The next issue is that your PageChooserBlock currently lets you select any page type. This means that when your template is rendered, it has no way to know up-front which page type to retrieve, so (in order to avoid unnecessary database lookups) it returns it as a basic Page instance which only contains the core fields that are common to all pages, such as title and slug - consequently, your image field will not be available through block.value.image. You can get around this by using block.value.specific.image which performs the extra database lookup to retrieve the complete page data - however, a more efficient approach is to specify the page type on the PageChooserBlock (assuming you've set up a dedicated page type for your case studies):

    ('case', blocks.PageChooserBlock(page_type=CaseStudyPage)),

Your final template code then becomes:

{% if page.case_studies %}
    {% for block in page.case_studies %}
         {% image block.value.image fill-50x50-c100 class="" %}
    {% endfor %}
{% endif %}