wagtail-auto-block-preview
While wagtail supports previews out of the box: https://docs.wagtail.org/en/stable/topics/streamfield.html#configuring-block-previews, it requires you to manually set preview values for each block.
This can be quite some work and it's easy to forget updating the preview values if you change this block.
The wagtail-auto-block-preview package tries to bring automatic preview values using Faker. This could save some time, but you can also make your previews consistent with this if you'd like.
Installation
pip install wagtail-auto-block-preview
Add "wagtail_auto_block_preview" to INSTALLED_APPS — Wagtail only discovers a package's wagtail_hooks.py (where the built-in fakers are registered) for apps listed there.
Usage
Subclass this package's StructBlock instead of Wagtail's own (alias the import if you need both in the same file). Each field gets a preview value generated automatically, based on its block type:
from wagtail import blocks
from wagtail.images.blocks import ImageChooserBlock
from wagtail_auto_block_preview import StructBlock, fake_image
class HeroBlock(StructBlock):
heading = blocks.CharBlock()
body = blocks.RichTextBlock()
image = ImageChooserBlock(preview_value=fake_image(ratio="16x9"))
heading/body get a generated sentence/paragraph; image uses an explicit preview_value here since a chooser built for a specific aspect ratio shouldn't get a random image squashed into it (see "Choosers" below for the default chooser behaviour).
Per field, in order — the first one that applies wins:
- An explicit
preview_valueon that field's own declaration. - An explicit
defaulton that field's own declaration — an intentional default already is a reasonable preview value. - A registered faker for that field's block type.
- The field's own native
get_preview_value()(Wagtail's own fallback).
Opt out via Meta when a field's own faked value isn't right for a particular block, without having to give it an explicit preview_value/default:
class HeroBlock(StructBlock):
heading = blocks.CharBlock()
body = blocks.RichTextBlock()
class Meta:
fake = False # disable entirely — falls back to Wagtail's own get_preview_value()
fake_exclude = ("body",) # disable for just these fields
This package's ListBlock works the same way as StructBlock — subclass it instead of Wagtail's own to get a few fake items generated instead of the single default-valued one Wagtail's own get_default() produces. A ListBlock's item type is singular and known, so each item is resolved the same way a StructBlock field is (item count: at least min_num, capped at max_num, 2 by default). Meta.fake = False disables generation the same way.
There's no faking StreamBlock — its content is an open-ended, editor-chosen set, so there's no principled way to auto-pick which block types to fake and in what combination. Hint it explicitly on the field instead, same as any other field-level override:
content = ContentStreamBlock(
default=[("heading", "Section heading"), ("rich_text", "<p>Example copy.</p>")],
)
Choosers
A ChooserBlock (page, snippet, document, or a custom one) is faked by picking an existing row from the block's own field.queryset — the same ModelChoiceField Wagtail already builds for form validation — rather than creating one, since there's no generically safe way to fabricate a valid instance of an arbitrary model without knowing its required fields. If you subclass ChooserBlock and override field to filter its queryset, that's respected automatically. If no rows exist yet, the field falls back to None, same as an empty chooser.
For PageChooserBlock and DocumentChooserBlock, the pick is narrowed to match what a content editor would actually be offered in the real chooser: the tree root is excluded, page type restrictions are applied, and any construct_page_chooser_queryset/construct_document_chooser_queryset hook a project has already registered runs too. Permission filtering isn't included — a faker has no request/user to filter by — but anything a project already restricts through those hooks is respected.
A block built via ChooserViewSet.get_block_class() (as DocumentChooserBlock is, and as a project's own custom choosers typically are) works the same way, since it's just a ChooserBlock subclass with target_model/widget set — no special-casing needed. What it won't get automatically is a custom viewset's own construct_<x>_chooser_queryset hook, since that hook name lives on the admin view class, not on the block. Reuse construct_chooser_queryset(queryset, hook_name) in your own registered faker to replicate that:
from wagtail_auto_block_preview import ValueFaker, construct_chooser_queryset
def widget_faker(block):
queryset = construct_chooser_queryset(block.field.queryset, "construct_widget_chooser_queryset")
return queryset.order_by("?").first()
@hooks.register("register_block_fakers")
def register_widget_faker():
return [(WidgetChooserBlock, ValueFaker(widget_faker))]
To hand-pick a specific instance (e.g. always the same demo snippet, or one filtered by some field), register a more specific faker — see "Overriding and adding fakers" below.
Overriding and adding fakers
Register a faker for a block type via the register_block_fakers hook, the same way Wagtail's own wagtail_hooks.py convention works:
from wagtail import hooks
from wagtail_auto_block_preview import ValueFaker
from myapp.blocks import RatingBlock
@hooks.register("register_block_fakers")
def register_my_fakers():
return [
(RatingBlock, ValueFaker(lambda block: 4)),
]
A faker registered for a base class also applies to any subclass that doesn't register its own, resolved by MRO — most-specific wins.
This also overrides a built-in faker: register your own for CharBlock, SnippetChooserBlock, or any other block type the built-in hook already covers, and yours wins — the built-in hook runs last by design.
If a faker raises, that one field falls back to its own native preview value instead of taking down the whole block's preview — the failure is logged as a warning so it doesn't go unnoticed.
Fabricating real objects
Some fields need a real, persisted, relational object — a chooser pointing at a snippet your code then calls .get_absolute_url() on, for example, where a bare stand-in object won't survive. FabricatedFaker runs its function inside a savepoint that's always rolled back afterwards, so nothing it creates is ever actually kept:
from wagtail_auto_block_preview import FabricatedFaker
from myapp.factories import ProductFactory
@hooks.register("register_block_fakers")
def register_product_faker():
return [(ProductChooserBlock, FabricatedFaker(lambda block: ProductFactory()))]
For a one-off fabrication needed in exactly one place, use fabricated() directly on a field instead of registering a hook:
highlighted_product = ProductChooserBlock(
preview_value=fabricated(lambda: ProductFactory()),
)
Fabrication mutes Django's model lifecycle signals (pre_save, post_save, pre_delete, post_delete, m2m_changed) for its duration, so it never triggers real side effects like search indexing or emails. If a project's own receiver lives on a different signal and also needs muting during fabrication, extend the set via a hook:
@hooks.register("register_muted_signals")
def mute_extra_signals():
return [my_app.signals.stock_changed]
Placeholder images
fake_image(width=None, height=None, ratio=None, label=None) returns a data-URI SVG placeholder — no database row, no static file, no urls.py wiring required.
Development
uv sync
uv run pytest tests/
uv run ruff check . && uv run ruff format --check .
uv run ty check wagtail_auto_block_preview/
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wagtail_auto_block_preview-0.1.0.tar.gz.
File metadata
- Download URL: wagtail_auto_block_preview-0.1.0.tar.gz
- Upload date:
- Size: 64.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6e778c24136ba524df9c7fba193c34368776fc2c0f02aa5d85d87df270407cd
|
|
| MD5 |
5015f67e6e2b4f7f63e64d37fcbeb4bb
|
|
| BLAKE2b-256 |
2a8eb8873f97f767c27bd142f9c995b52a279cbbee6a5dbb3ace25b25720545a
|
Provenance
The following attestation bundles were made for wagtail_auto_block_preview-0.1.0.tar.gz:
Publisher:
publish.yml on joeyjurjens/wagtail-auto-block-preview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wagtail_auto_block_preview-0.1.0.tar.gz -
Subject digest:
c6e778c24136ba524df9c7fba193c34368776fc2c0f02aa5d85d87df270407cd - Sigstore transparency entry: 2498961964
- Sigstore integration time:
-
Permalink:
joeyjurjens/wagtail-auto-block-preview@82842038af66bd2a4a9c232b6767718574244133 -
Branch / Tag:
refs/tags/0.1.0 - Owner: https://github.com/joeyjurjens
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@82842038af66bd2a4a9c232b6767718574244133 -
Trigger Event:
release
-
Statement type:
File details
Details for the file wagtail_auto_block_preview-0.1.0-py3-none-any.whl.
File metadata
- Download URL: wagtail_auto_block_preview-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7c25e819fa423a172b95617b6bd579c6d31a979ef54b30031d354efc44339fb
|
|
| MD5 |
a6bb7c8da93d1b50e33bf6f5fb66d39d
|
|
| BLAKE2b-256 |
612575fcca6f656170a84c11e24287f410864b97e96348a44fccf21c2a625058
|
Provenance
The following attestation bundles were made for wagtail_auto_block_preview-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on joeyjurjens/wagtail-auto-block-preview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wagtail_auto_block_preview-0.1.0-py3-none-any.whl -
Subject digest:
b7c25e819fa423a172b95617b6bd579c6d31a979ef54b30031d354efc44339fb - Sigstore transparency entry: 2498962232
- Sigstore integration time:
-
Permalink:
joeyjurjens/wagtail-auto-block-preview@82842038af66bd2a4a9c232b6767718574244133 -
Branch / Tag:
refs/tags/0.1.0 - Owner: https://github.com/joeyjurjens
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@82842038af66bd2a4a9c232b6767718574244133 -
Trigger Event:
release
-
Statement type: