Daniel Herrera
Daniel Herrera

Reputation: 23

Rendering streamfield block a certain way if booleanBlock is True

Hello I'm currently new to django/wagtail. I'm working on an about page that shows previous and current work/positions. I've made the positions streamfield blocks since the amount of experience isn't limited. Here is the code to my models.

#Create experience block 
class ExperienceBlockStruct(StructBlock):
    position_title = CharBlock(help_text="Enter a previous position title.")
    description = CharBlock(help_text="Job description")
    current_position = BooleanBlock(required=False, help_text="Check if 
    current position")

class Meta:
    template = 'blocks/experience_block.html'


class ExperienceBlock(StreamBlock):
    experience = ExperienceBlockStruct(icon="form")

And here is the page where I use the models

class About(Page):
    profile_pic = "some image reduced code bc it currently works"
    bio = RichTextField(blank=True)
    resume = "some document reduced code bc it currently works"
    experience = StreamField(ExperienceBlock())
    content_panels = Page.content_panels + [
        ImageChooserPanel('profile_pic'),
        FieldPanel('bio'),
        DocumentChooserPanel('resume'),
        StreamFieldPanel('experience'),
    ]

Now the issue I'm having is how to render the blocks where the current_position = True in a different area than those that are not. I've tried

templates/about.html
{% for block in page.experience %}
  {% if block.current_position %}
    {% include_block block %}
  {% endif %}
{% endfor %}

But that doesnt render anything. I've also tried to

<div class="experience">
  {% if value.current_position %}
    {{ value.position_title }}
  {% else %}
    {{ value.position_title }}
  {% endif %}
</div>

but that creates a new div for every block. What I would like to achieve is something like in blocks/experience_block.html

<div>
  Current position(s): {% blocks with current_postion == True %}
</div>   

<div>
  Past position(s): {% blocks with current_postion == False %}
</div>  

How could I go about achieving something like this?

Upvotes: 1

Views: 642

Answers (1)

gasman
gasman

Reputation: 25227

Your first template snippet was almost correct - you just need to check block.value.current_position rather than block.current_position:

{% for block in page.experience %}
    {% if block.value.current_position %}
        {% include_block block %}
    {% endif %}
{% endfor %}

This is because looping over page.experience gives you a series of BoundBlock objects that tell you the block_type (always 'experience' in your case) alongside the block value. See BoundBlocks and values for a more detailed explanation.

You can do the same thing in your experience_block.html template (using {% for block in value %} rather than {% for block in page.experience %}) - although note that the Meta template definition needs to go on ExperienceBlock rather than ExperienceBlockStruct, because that's the one that has access to the full list to loop over, rather than a single record.

To make things neater, I'd suggest defining a get_context method on the block, so that you're doing the data manipulation within Python code rather than inside the template...

class ExperienceBlock(StreamBlock):
    experience = ExperienceBlockStruct(icon="form")

    def get_context(self, value, parent_context=None):
        context = super(ExperienceBlock, self).get_context(value, parent_context=parent_context)
        context['current_positions'] = [block for block in value if block.value.current_position]
        context['past_positions'] = [block for block in value if not block.value.current_position]
        return context

    class Meta:
        template = 'blocks/experience_block.html'

This will make the variables current_positions and past_positions available on the template.

Upvotes: 1

Related Questions