.. _streamfield: Freeform page content using StreamField ======================================= StreamField provides a content editing model suitable for pages that do not follow a fixed structure -- such as blog posts or news stories -- where the text may be interspersed with subheadings, images, pull quotes and video. It's also suitable for more specialised content types, such as maps and charts (or, for a programming blog, code snippets). In this model, these different content types are represented as a sequence of 'blocks', which can be repeated and arranged in any order. For further background on StreamField, and why you would use it instead of a rich text field for the article body, see the blog post `Rich text fields and faster horses `__. StreamField also offers a rich API to define your own block types, ranging from simple collections of sub-blocks (such as a 'person' block consisting of first name, surname and photograph) to completely custom components with their own editing interface. Within the database, the StreamField content is stored as JSON, ensuring that the full informational content of the field is preserved, rather than just an HTML representation of it. Using StreamField ----------------- ``StreamField`` is a model field that can be defined within your page model like any other field: .. code-block:: python from django.db import models from wagtail.wagtailcore.models import Page from wagtail.wagtailcore.fields import StreamField from wagtail.wagtailcore import blocks from wagtail.wagtailadmin.edit_handlers import FieldPanel, StreamFieldPanel from wagtail.wagtailimages.blocks import ImageChooserBlock class BlogPage(Page): author = models.CharField(max_length=255) date = models.DateField("Post date") body = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ('image', ImageChooserBlock()), ]) content_panels = Page.content_panels + [ FieldPanel('author'), FieldPanel('date'), StreamFieldPanel('body'), ] Note: StreamField is not backwards compatible with other field types such as RichTextField. If you need to migrate an existing field to StreamField, refer to :ref:`streamfield_migrating_richtext`. The parameter to ``StreamField`` is a list of ``(name, block_type)`` tuples. 'name' is used to identify the block type within templates and the internal JSON representation (and should follow standard Python conventions for variable names: lower-case and underscores, no spaces) and 'block_type' should be a block definition object as described below. (Alternatively, ``StreamField`` can be passed a single ``StreamBlock`` instance - see `Structural block types`_.) This defines the set of available block types that can be used within this field. The author of the page is free to use these blocks as many times as desired, in any order. Basic block types ----------------- All block types accept the following optional keyword arguments: ``default`` The default value that a new 'empty' block should receive. ``label`` The label to display in the editor interface when referring to this block - defaults to a prettified version of the block name (or, in a context where no name is assigned - such as within a ``ListBlock`` - the empty string). ``icon`` The name of the icon to display for this block type in the menu of available block types. For a list of icon names, see the Wagtail style guide, which can be enabled by adding ``wagtail.contrib.wagtailstyleguide`` to your project's ``INSTALLED_APPS``. ``template`` The path to a Django template that will be used to render this block on the front end. See `Template rendering`_. The basic block types provided by Wagtail are as follows: CharBlock ~~~~~~~~~ ``wagtail.wagtailcore.blocks.CharBlock`` A single-line text input. The following keyword arguments are accepted: ``required`` (default: True) If true, the field cannot be left blank. ``max_length``, ``min_length`` Ensures that the string is at most or at least the given length. ``help_text`` Help text to display alongside the field. TextBlock ~~~~~~~~~ ``wagtail.wagtailcore.blocks.TextBlock`` A multi-line text input. As with ``CharBlock``, the keyword arguments ``required``, ``max_length``, ``min_length`` and ``help_text`` are accepted. EmailBlock ~~~~~~~~~~ ``wagtail.wagtailcore.blocks.EmailBlock`` A single-line email input that validates that the email is a valid Email Address. The keyword arguments ``required`` and ``help_text`` are accepted. For an example of ``EmailBlock`` in use, see :ref:`streamfield_personblock_example` IntegerBlock ~~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.IntegerBlock`` A single-line integer input that validates that the integer is a valid whole number. The keyword arguments ``required``, ``max_value``, ``min_value`` and ``help_text`` are accepted. For an example of ``IntegerBlock`` in use, see :ref:`streamfield_personblock_example` FloatBlock ~~~~~~~~~~ ``wagtail.wagtailcore.blocks.FloatBlock`` A single-line Float input that validates that the value is a valid floating point number. The keyword arguments ``required``, ``max_value`` and ``min_value`` are accepted. DecimalBlock ~~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.DecimalBlock`` A single-line decimal input that validates that the value is a valid decimal number. The keyword arguments ``required``, ``max_value``, ``min_value``, ``max_digits`` and ``decimal_places`` are accepted. For an example of ``DecimalBlock`` in use, see :ref:`streamfield_personblock_example` RegexBlock ~~~~~~~~~~ ``wagtail.wagtailcore.blocks.RegexBlock`` A single-line text input that validates a string against a regex expression. The regular expression used for validation must be supplied as the first argument, or as the keyword argument ``regex``. To customise the message text used to indicate a validation error, pass a dictionary as the keyword argument ``error_messages`` containing either or both of the keys ``required`` (for the message shown on an empty value) or ``invalid`` (for the message shown on a non-matching value): .. code-block:: python blocks.RegexBlock(regex=r'^[0-9]{3}$', error_message={ 'invalid': "Not a valid library card number." }) The keyword arguments ``regex``, ``required``, ``max_length``, ``min_length`` and ``error_messages`` are accepted. URLBlock ~~~~~~~~ ``wagtail.wagtailcore.blocks.URLBlock`` A single-line text input that validates that the string is a valid URL. The keyword arguments ``required``, ``max_length``, ``min_length`` and ``help_text`` are accepted. BooleanBlock ~~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.BooleanBlock`` A checkbox. The keyword arguments ``required`` and ``help_text`` are accepted. As with Django's ``BooleanField``, a value of ``required=True`` (the default) indicates that the checkbox must be ticked in order to proceed. For a checkbox that can be ticked or unticked, you must explicitly pass in ``required=False``. DateBlock ~~~~~~~~~ ``wagtail.wagtailcore.blocks.DateBlock`` A date picker. The keyword arguments ``required`` and ``help_text`` are accepted. TimeBlock ~~~~~~~~~ ``wagtail.wagtailcore.blocks.TimeBlock`` A time picker. The keyword arguments ``required`` and ``help_text`` are accepted. DateTimeBlock ~~~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.DateTimeBlock`` A combined date / time picker. The keyword arguments ``required`` and ``help_text`` are accepted. RichTextBlock ~~~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.RichTextBlock`` A WYSIWYG editor for creating formatted text including links, bold / italics etc. RawHTMLBlock ~~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.RawHTMLBlock`` A text area for entering raw HTML which will be rendered unescaped in the page output. The keyword arguments ``required``, ``max_length``, ``min_length`` and ``help_text`` are accepted. .. WARNING:: When this block is in use, there is nothing to prevent editors from inserting malicious scripts into the page, including scripts that would allow the editor to acquire administrator privileges when another administrator views the page. Do not use this block unless your editors are fully trusted. ChoiceBlock ~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.ChoiceBlock`` A dropdown select box for choosing from a list of choices. The following keyword arguments are accepted: ``choices`` A list of choices, in any format accepted by Django's ``choices`` parameter for model fields: https://docs.djangoproject.com/en/stable/ref/models/fields/#field-choices ``required`` (default: True) If true, the field cannot be left blank. ``help_text`` Help text to display alongside the field. ``ChoiceBlock`` can also be subclassed to produce a reusable block with the same list of choices everywhere it is used. For example, a block definition such as: .. code-block:: python blocks.ChoiceBlock(choices=[ ('tea', 'Tea'), ('coffee', 'Coffee'), ], icon='cup') could be rewritten as a subclass of ChoiceBlock: .. code-block:: python class DrinksChoiceBlock(blocks.ChoiceBlock): choices = [ ('tea', 'Tea'), ('coffee', 'Coffee'), ] class Meta: icon = 'cup' ``StreamField`` definitions can then refer to ``DrinksChoiceBlock()`` in place of the full ``ChoiceBlock`` definition. PageChooserBlock ~~~~~~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.PageChooserBlock`` A control for selecting a page object, using Wagtail's page browser. The following keyword arguments are accepted: ``required`` (default: True) If true, the field cannot be left blank. ``target_model`` (default: Page) Restrict choices to a single Page type. ``can_choose_root`` (default: False) If true, the editor can choose the tree root as a page. Normally this would be undesirable, since the tree root is never a usable page, but in some specialised cases it may be appropriate. For example, a block providing a feed of related articles could use a PageChooserBlock to select which subsection of the site articles will be taken from, with the root corresponding to 'everywhere'. DocumentChooserBlock ~~~~~~~~~~~~~~~~~~~~ ``wagtail.wagtaildocs.blocks.DocumentChooserBlock`` A control to allow the editor to select an existing document object, or upload a new one. The keyword argument ``required`` is accepted. ImageChooserBlock ~~~~~~~~~~~~~~~~~ ``wagtail.wagtailimages.blocks.ImageChooserBlock`` A control to allow the editor to select an existing image, or upload a new one. The keyword argument ``required`` is accepted. SnippetChooserBlock ~~~~~~~~~~~~~~~~~~~ ``wagtail.wagtailsnippets.blocks.SnippetChooserBlock`` A control to allow the editor to select a snippet object. Requires one positional argument: the snippet class to choose from. The keyword argument ``required`` is accepted. EmbedBlock ~~~~~~~~~~ ``wagtail.wagtailembeds.blocks.EmbedBlock`` A field for the editor to enter a URL to a media item (such as a YouTube video) to appear as embedded media on the page. The keyword arguments ``required``, ``max_length``, ``min_length`` and ``help_text`` are accepted. Structural block types ---------------------- In addition to the basic block types above, it is possible to define new block types made up of sub-blocks: for example, a 'person' block consisting of sub-blocks for first name, surname and image, or a 'carousel' block consisting of an unlimited number of image blocks. These structures can be nested to any depth, making it possible to have a structure containing a list, or a list of structures. StructBlock ~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.StructBlock`` A block consisting of a fixed group of sub-blocks to be displayed together. Takes a list of ``(name, block_definition)`` tuples as its first argument: .. code-block:: python ('person', blocks.StructBlock([ ('first_name', blocks.CharBlock(required=True)), ('surname', blocks.CharBlock(required=True)), ('photo', ImageChooserBlock()), ('biography', blocks.RichTextBlock()), ], icon='user')) Alternatively, the list of sub-blocks can be provided in a subclass of StructBlock: .. code-block:: python class PersonBlock(blocks.StructBlock): first_name = blocks.CharBlock(required=True) surname = blocks.CharBlock(required=True) photo = ImageChooserBlock() biography = blocks.RichTextBlock() class Meta: icon = 'user' The ``Meta`` class supports the properties ``default``, ``label``, ``icon`` and ``template``, which have the same meanings as when they are passed to the block's constructor. This defines ``PersonBlock()`` as a block type that can be re-used as many times as you like within your model definitions: .. code-block:: python body = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ('image', ImageChooserBlock()), ('person', PersonBlock()), ]) Further options are available for customising the display of a ``StructBlock`` within the page editor - see :ref:`custom_editing_interfaces_for_structblock`. ListBlock ~~~~~~~~~ ``wagtail.wagtailcore.blocks.ListBlock`` A block consisting of many sub-blocks, all of the same type. The editor can add an unlimited number of sub-blocks, and re-order and delete them. Takes the definition of the sub-block as its first argument: .. code-block:: python ('ingredients_list', blocks.ListBlock(blocks.CharBlock(label="Ingredient"))) Any block type is valid as the sub-block type, including structural types: .. code-block:: python ('ingredients_list', blocks.ListBlock(blocks.StructBlock([ ('ingredient', blocks.CharBlock(required=True)), ('amount', blocks.CharBlock()), ]))) StreamBlock ~~~~~~~~~~~ ``wagtail.wagtailcore.blocks.StreamBlock`` A block consisting of a sequence of sub-blocks of different types, which can be mixed and reordered at will. Used as the overall mechanism of the StreamField itself, but can also be nested or used within other structural block types. Takes a list of ``(name, block_definition)`` tuples as its first argument: .. code-block:: python ('carousel', blocks.StreamBlock( [ ('image', ImageChooserBlock()), ('quotation', blocks.StructBlock([ ('text', blocks.TextBlock()), ('author', blocks.CharBlock()), ])), ('video', EmbedBlock()), ], icon='cogs' )) As with StructBlock, the list of sub-blocks can also be provided as a subclass of StreamBlock: .. code-block:: python class CarouselBlock(blocks.StreamBlock): image = ImageChooserBlock() quotation = blocks.StructBlock([ ('text', blocks.TextBlock()), ('author', blocks.CharBlock()), ]) video = EmbedBlock() class Meta: icon='cogs' Since ``StreamField`` accepts an instance of ``StreamBlock`` as a parameter, in place of a list of block types, this makes it possible to re-use a common set of block types without repeating definitions: .. code-block:: python class HomePage(Page): carousel = StreamField(CarouselBlock()) .. _streamfield_personblock_example: Example: ``PersonBlock`` ------------------------ This example demonstrates how the basic block types introduced above can be combined into a more complex block type based on ``StructBlock``: .. code-block:: python from wagtail.wagtailcore import blocks class PersonBlock(blocks.StructBlock): name = blocks.CharBlock() height = blocks.DecimalBlock() age = blocks.IntegerBlock() email = blocks.EmailBlock() class Meta: template = 'blocks/person_block.html' .. _streamfield_template_rendering: Template rendering ------------------ StreamField provides an HTML representation for the stream content as a whole, as well as for each individual block. To include this HTML into your page, use the ``{% include_block %}`` tag: .. code-block:: html+django {% load wagtailcore_tags %} {% include_block page.body %} In the default rendering, each block of the stream is wrapped in a ``
`` element (where ``my_block_name`` is the block name given in the StreamField definition). If you wish to provide your own HTML markup, you can instead iterate over the field's value, and invoke ``{% include_block %}`` on each block in turn: .. code-block:: html+django {% load wagtailcore_tags %}
{% for block in page.body %}
{% include_block block %}
{% endfor %}
For more control over the rendering of specific block types, each block object provides ``block_type`` and ``value`` properties: .. code-block:: html+django {% load wagtailcore_tags %}
{% for block in page.body %} {% if block.block_type == 'heading' %}

{{ block.value }}

{% else %}
{% include_block block %}
{% endif %} {% endfor %}
By default, each block is rendered using simple, minimal HTML markup, or no markup at all. For example, a CharBlock value is rendered as plain text, while a ListBlock outputs its child blocks in a `