Search code examples
wagtailwagtail-snippet

Wagtail Admin: How to Add ReadOnlyBlocks to show snippets fields values in a StructBlock


I have a Snippet model(SampleSnippet) with fields field_a, field_b, and field_c. And I am using it in a StructBlock like:

class SampleBlock(blocks.StructBlock):
    service_snippet = SnippetChooserBlock(SampleSnippet)
    ...

Now I want to show some of the SampleSnippet fields(field_a and field_b) in SampleBlock after saving the SampleBlock for the first time(after saving the snippet) on the wagtail admin site. How can I achieve this? I looked around a lot but couldn't find a similar issue.

If it were a model/snippet, I could have used property with ReadOnlyPanel but in the case of a StructBlock, I am stuck and not getting any ideas. If anybody knows any way to achieve this, please help me out. Thanks in advance.


Solution

  • This is going to be quite difficult, since in current Wagtail versions (>=2.13) the StreamField editing UI is populated client-side in Javascript - as such, there are some extra steps to make the necessary data available to the client-side code, and the standard Django form / template mechanisms won't be available.

    A simple workaround, if the fields aren't too long, would be to define the snippet's __str__ method to include the desired data - this will then display any time the snippet is shown in the admin.

    For a full solution, I'd suggest this approach:

    • Set up a custom form_template for your StructBlock as detailed in Custom editing interfaces for StructBlock, with placeholder <div> elements to contain your additional data.

    • Override the StructBlock's get_form_state so that the returned dict (which will be used to populate the form template on the client side) includes your additional fields - something like:

      def get_form_state(self, value):
          data = super().get_form_state(value)
          data['field_a'] = value['service_snippet'].field_a
          data['field_b'] = value['service_snippet'].field_b
          return data
      
    • Set up a custom JS adapter following the steps in Additional JavaScript on StructBlock forms. In the final render method, the data you returned from get_form_state will be available as initialState, and you can use this to populate the placeholder <div>s in the template.