Lazy-loading StreamField and StreamBlock for Wagtail that defers block instantiation to prevent circular imports and reduces migration bloat
Project description
wagtail-lazy-streamfield
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
JSONFieldstorage; 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
Release history Release notifications | RSS feed
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_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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db53c6a6bdd2607adb77e8c1c4cd8ead95d73ad3a30a867261315a096095e6d1
|
|
| MD5 |
65fdbfb091b0671b33e89c9295b7804a
|
|
| BLAKE2b-256 |
0ece6da1a24cb70a404db726e42463348f7f89faf3caa46ecebf3627d44cf39d
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee0f02b9b638b711b4e91353e12048d41ba141955129e044090573a070d64d31
|
|
| MD5 |
2461a77fa8d49d0c468e90d8391ddcde
|
|
| BLAKE2b-256 |
ff871ffb0b08603c1436413bf871817f548917aee14b47fb1834d523c02fe8f7
|