In order to avoid rendering markdown each time a page was viewed, I had two TextFields in my Page model. One in which to enter the markdown in the admin site and a second hidden TextField in which I stored the rendered html during Page save.
Now, I'm trying to add similar functionality to a Markdown StructBlock for use in StreamField. Currently, I'm rendering the html on every page view. AIUI the instances of Blocks are stored as (name, value) tuples.
Is it feasible/sensible to add a third 'rendered' element in the stored tuple plus override methods in some new derived Block class?
Or is this something possible and better addressed with (partial) page caching?
Within the database, a StructBlock is stored as a dict, so if your markdown block is based on StructBlock, adding an extra key to that dict would make most sense. (You're partly correct that items within a StreamBlock are often represented as (name, value) tuples, but making use of that would involve digging deeply into the interaction between StreamBlock and its children, and I think that would overcomplicate things here.)
All blocks implement a pair of methods
get_prep_value(value)
(which is used when writing the block to the database, and converts the native Python value of a block to a JSON-serialisable version that can be stored in the database) andto_python(value)
(which converts it back again on retrieving it from the database). With that in mind, there are two steps to implement here:get_prep_value
to generate the rendered version and insert that into the database representationto_python
to ensure that the rendered version is preserved when unpacking the database representation (which won't happen automatically, because StructBlock will only unpack the child blocks it knows about, and the rendered HTML value isn't one of them)There's an extra complication with the second part, because StructBlock implements a
bulk_to_python(values)
method as a performance optimisation - this unpacks a list of values in one go, to take advantage of any child blocks that are handled more efficiently that way (such as ones that need database lookups), and bypasses the usualto_python
method, so you'll need to override that one too.Assuming your starting point is something like:
you want something like:
and then that should hopefully make
rendered_text
available alongsidemarkdown_text
andsome_other_property
when accessing the block value on your template.