Skip to main content

Lazy-loading StreamField and StreamBlock for Wagtail that defers block instantiation to prevent circular imports and reduces migration bloat

Project description

wagtail-lazy-streamfield

PyPI License

This module provides a lazy-loading StreamField for Wagtail. Resolves circular import issues between blocks and models, and keeps migrations free of block structure bloat.

The Circular Import Problem

In Wagtail projects, blocks often become interdependent. A CardBlock might reference a page model that has a StreamField using CardBlock. This causes ImportError at startup:

# Fails if CardBlock imports this file
from .blocks import CardBlock

class MyPage(Page):
    body = StreamField([
        ('card', CardBlock()),  # Instantiation requires immediate import
    ])

With LazyStreamField, block paths are strings. Resolution happens at runtime, not import time:

class MyPage(Page):
    body = LazyStreamField(StreamBlockDefinition(
        ('card', 'myapp.blocks.CardBlock'),
    ))

The Migration Bloat Problem

Wagtail freezes the entire StreamField block structure into migration files. Complex sites can have migrations exceeding 10,000 lines. This makes migrations slow to generate, hard to review, and prone to merge conflicts.

LazyStreamField excludes block definitions from migration serialization:

# migrations/0001_initial.py
operations = [
    migrations.AddField(
        model_name='blogpage',
        name='content',
        field=lazy_streamfield.streamfield.LazyStreamField(blank=True, null=True),
    ),
]

Installation

pip install wagtail-lazy-streamfield

Usage

Define Blocks

Use StreamBlockDefinition with string paths instead of instantiating blocks directly:

# blocks.py
from lazy_streamfield import StreamBlockDefinition

BASE_BLOCKS = StreamBlockDefinition(
    ("text", "myapp.blocks.TextBlock"),
    ("image", "myapp.blocks.ImageBlock"),
)

# Combine definitions with |
MEDIA_BLOCKS = StreamBlockDefinition(
    ("video", "myapp.blocks.VideoBlock"),
)

ALL_BLOCKS = BASE_BLOCKS | MEDIA_BLOCKS

Use in Models

Replace StreamField with LazyStreamField:

# models.py
from wagtail.models import Page
from lazy_streamfield import LazyStreamField
from .blocks import ALL_BLOCKS

class BlogPage(Page):
    content = LazyStreamField(ALL_BLOCKS, blank=True)

Nested Blocks

Use LazyStreamBlock inside a StructBlock to prevent recursion or break import cycles:

# blocks.py
from wagtail.blocks import StructBlock
from lazy_streamfield import LazyStreamBlock, StreamBlockDefinition

NESTED_BLOCKS = StreamBlockDefinition(
    ("card", "myapp.blocks.CardBlock"),
)

class CardBlock(StructBlock):
    content = LazyStreamBlock(NESTED_BLOCKS)

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

[1.0.1] - 2026-01-19

Fixed

  • Fixed type annotations in StreamBlockDefinition to use Block instead of BaseBlock (which is a metaclass).

Added

  • Added ty type checker to CI and runtests.sh.
  • Added pre-commit configuration with ruff, ty, and standard hooks.
  • Added [dependency-groups] for dev tools.

Changed

  • Consolidated CI lint checks into single step using project dependencies.
  • Cleaned up ruff configuration, removed unnecessary ignore rules.
  • PyPI description now includes both README and CHANGELOG via hatch-fancy-pypi-readme.

[1.0.0] - 2026-01-17

Added

  • Initial release of wagtail-lazy-streamfield.
  • LazyStreamField for deferring block instantiation in Page models.
  • LazyStreamBlock for lazy loading within nested blocks (e.g., StructBlock).
  • StreamBlockDefinition helper for defining block import paths.
  • Prevention of circular imports via runtime importing.
  • Exclusion of block definitions from Django migrations to reduce bloat.
  • Comprehensive test suite and type hints.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wagtail_lazy_streamfield-1.0.1.tar.gz (46.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wagtail_lazy_streamfield-1.0.1-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file wagtail_lazy_streamfield-1.0.1.tar.gz.

File metadata

  • Download URL: wagtail_lazy_streamfield-1.0.1.tar.gz
  • Upload date:
  • Size: 46.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for wagtail_lazy_streamfield-1.0.1.tar.gz
Algorithm Hash digest
SHA256 1771c8f7d7905436a9da31090655ee8f9a390d8d1d425ddaed23b17eb3c7f6a2
MD5 94302415bc5b5e8c9ddfd5aaf83f68c7
BLAKE2b-256 f65bcecf937fae18e9c685c7bb555bee34885f962c7191a7eebe68dd7ca93157

See more details on using hashes here.

File details

Details for the file wagtail_lazy_streamfield-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: wagtail_lazy_streamfield-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 9.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for wagtail_lazy_streamfield-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5bcb95329044a874ce90c9018f6d6ec90c673238d18ad15fc56211d714fef72c
MD5 566701e45da238abebbba1056d713368
BLAKE2b-256 1dccdf87ae63435a251007dfcb9c1bb19267f1742366cf11f00921cd46e00afb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page