wagtailwagtail-streamfield

Wagtail - Add data to streamfield CharBlock on save()


I'm trying to automatically fill in a specific charblock on a streamfield I have created on save and I can get it to change but not save because when the page refreshes the new data is not there.

    def save(self, *args, **kwargs):
        if kwargs.get('update_fields'):
            if self.auto_update:
                for product in self.product_details.raw_data:
                    product_name = product['value']['product_name']
                    product_url = product['value']['product_url']

                    # I'm trying to set the field data here
                    product['value']['product_snippet_url'] = 'Test'
                    # when I print, I see the 'Test' value in the dict
                    print(product)          
        else:
            # Do stuff on publish()
            pass

        return super().save(*args, **kwargs)
    # Streamfield Block
    class ProductNameAndUrlBlock(blocks.StructBlock):
        product_name = blocks.CharBlock(required=True, help_text='Add product name')
        product_url =  blocks.URLBlock(required=True, help_text='Add Product URL')
        product_snippet_url = blocks.CharBlock(required=False, help_text='Link to snippet')

The above code is for testing purposes, my end goal is to insert the url of the related snippet there and then use JS to turn it into a button so when someone clicks on it, it links to the snippet page.


Solution

  • Writing back to the stream's raw_data property will not reliably save the data. raw_data is a "backup" copy of the data as retrieved from the database, in a simplified format - for example, a PageChooserBlock value is stored there as a plain ID rather than a Page object. Once data is read or written through the stream's standard methods (e.g. looping over for block in self.product_details or writing self.product_details[0] = ...), the raw_data entry is treated as stale and not looked at again.

    The correct approach is to read and write the stream itself as a list, rather than going through raw_data:

                for product in self.product_details:
                    product_name = product.value['product_name']
                    product_url = product.value['product_url']
    
                    # I'm trying to set the field data here
                    product.value['product_snippet_url'] = 'Test'