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

A lightweight utility for Wagtail that defers StreamField block instantiation. It resolves circular import issues in complex block dependencies and eliminates block definitions from Django migrations to keep them clean and manageable.

Features

  • Lazy Loading: Defers block import and instantiation until runtime, preventing circular import errors.
  • Clean Migrations: Excludes block definitions from migration files, reducing file size and generation time.
  • Zero Database Overhead: Works with standard JSONField storage; no database schema changes required.
  • Typed: Fully type-hinted and PEP 561 compatible.

Installation

Install via pip:

pip install wagtail-lazy-streamfield

Usage

1. Define Blocks

Instead of instantiating blocks directly, define them using StreamBlockDefinition and string paths. This decouples your models from your block implementations.

# blocks.py
from lazy_streamfield import StreamBlockDefinition

# Define blocks using their python import path
BASE_BLOCKS = StreamBlockDefinition(
    ("text", "myapp.blocks.TextBlock"),
    ("image", "myapp.blocks.ImageBlock"),
)

# You can combine definitions using the | operator
MEDIA_BLOCKS = StreamBlockDefinition(
    ("video", "myapp.blocks.VideoBlock"),
)

ALL_BLOCKS = BASE_BLOCKS | MEDIA_BLOCKS

2. Use LazyStreamField in Models

Replace standard 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)

3. Use LazyStreamBlock for Nesting

If you need lazy loading inside a StructBlock (e.g., to prevent recursion or just to tidy up), use LazyStreamBlock.

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

# This references the block below, which would normally cause a circular import
NESTED_BLOCKS = StreamBlockDefinition(
    ("card", "myapp.blocks.CardBlock"),
)

class CardBlock(StructBlock):
    # ... fields ...
    # Use LazyStreamBlock for nested stream content
    content = LazyStreamBlock(NESTED_BLOCKS)

Rationale

The Circular Import Problem

In large Wagtail projects, blocks often become interdependent. For example, a PageBlock might import a Page model, which has a StreamField that uses PageBlock. This cycle causes ImportError at startup.

Standard Wagtail:

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

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

With LazyStreamField:

# Safe: "myapp.blocks.CardBlock" is just a string at module level
body = LazyStreamField(BLOCKS)

The Migration Bloat Problem

Wagtail freezes the entire StreamField block structure into Django migration files. For complex sites, a single migration can easily exceed 10,000 lines of code. This makes migrations slow to generate, hard to review, and prone to conflicts.

LazyStreamField strips block definitions from the migration serialization, resulting in concise migrations:

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

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.0.tar.gz (41.1 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.0-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: wagtail_lazy_streamfield-1.0.0.tar.gz
  • Upload date:
  • Size: 41.1 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.0.tar.gz
Algorithm Hash digest
SHA256 db53c6a6bdd2607adb77e8c1c4cd8ead95d73ad3a30a867261315a096095e6d1
MD5 65fdbfb091b0671b33e89c9295b7804a
BLAKE2b-256 0ece6da1a24cb70a404db726e42463348f7f89faf3caa46ecebf3627d44cf39d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: wagtail_lazy_streamfield-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 9.2 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ee0f02b9b638b711b4e91353e12048d41ba141955129e044090573a070d64d31
MD5 2461a77fa8d49d0c468e90d8391ddcde
BLAKE2b-256 ff871ffb0b08603c1436413bf871817f548917aee14b47fb1834d523c02fe8f7

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