Wagtail Seeder
Development-data seeder for Wagtail 7.x (Python 3.10 and later). It creates representative pages, media, snippets and settings by inspecting installed Wagtail models.
Installation
Install from PyPI:
python -m pip install wagtail-seeder
Add "wagtail_seeder" to INSTALLED_APPS. Configure
an explicit environment; the package fails closed when it is omitted or unsupported:
WAGTAIL_SEEDER = {
"ENVIRONMENT": "dev",
"HOMEPAGE_MODEL": "pages.HomePage",
"DEFAULT_SITE_PORT": 80, # use 8000 for Django's runserver
}
Apply the project's migrations, then inspect and seed:
python manage.py migrate
python manage.py inspect_wagtail_seed --format=json --require-complete
python manage.py seed_wagtail --confirm --require-complete
python manage.py seed_wagtail_pages --page-type pages.ArticlePage
seed_wagtail is destructive: it removes Wagtail Site objects and pages below
its technical root. Use an isolated development database. seed_wagtail_pages
preserves existing pages and reuses representatives when the configured count is met.
During a full reset, nullable protected links into the old page tree are detached
and populated again. Required protected links block deletion; the original sites,
pages and detached links are restored when deletion fails.
Selected page types can also be seeded through Seeder in the Wagtail admin
without resetting the site. The destructive reset is only available through the CLI.
The dashboard is available to active users with the explicitly assigned wagtail_seeder.run_seeder permission.
Superusers also need a direct or group grant; their automatic Django permission
bypass does not apply. Existing users are not granted access on upgrade.
CLI commands require the explicit allowed environment and do not impersonate a user.
After migrate, assign Can run Wagtail Seeder through Django's user/group
administration or Wagtail's group permissions. Users also need normal Wagtail
admin access. Removing the grant immediately hides the menu and blocks seed requests.
The dashboard includes a moving loading bar and elapsed time during a seed,
searchable page selection, and a searchable, sortable result table with status
filters. The loading bar indicates activity rather than a completion percentage.
The report starts collapsed at the top of the dashboard and can be removed with
Rapport wissen. It is shown once after a seed and disappears when the page is
refreshed or left. Each concrete page has one result row with expandable details;
other results are grouped separately. Report items include optional page_id,
page_title and page_model metadata, plus is_summary (default False). Summary
rows are excluded from outcome counts so a failure is counted once.
Sites and languages
A single-site project needs only the configuration above. Use SITE_ROOTS for
multiple public sites or languages. Every root creates its own Site; descendants,
page links, settings and translatable snippets stay within their applicable scope.
WAGTAIL_SEEDER = {
"ENVIRONMENT": "dev",
"DEFAULT_SITE_PORT": 80,
"SITE_ROOTS": [
{
"page_model": "pages.HomePage",
"hostname": "localhost",
"language_code": "nl",
"is_default_site": True,
},
{
"page_model": "pages.HomePage",
"hostname": "en.localhost",
"language_code": "en",
},
],
}
language_code must be in Wagtail's content languages. It resolves or creates a
Locale; it does not enable translation settings or translate text. Omit it to use
the project's default content language. Do not put a language string in
field_values["locale"]: that field expects a Locale instance.
Each root requires page_model; optional values include hostname, port,
site_name, is_default_site, slug and protected field_values. Give it a unique
key when another configured root uses parent_page_key.
SEED_ROOT_PAGES uses the same page configuration without creating another Site.
Use it only for technical branches that otherwise cannot be reached.
parent_page_model or parent_page_key deliberately selects an explicit parent;
force_root: True deliberately overrides creation restrictions at the technical
root. An explicit parent and force_root cannot be combined.
Generation and validation
The seeder creates draft page structures before filling dependencies and publishing.
Editor presets keep their existing text and structure while empty required fields
and nested blocks are filled. Existing valid relationships are preserved, including
relationships in explicitly declared many-to-many intermediate models.
Scalar fields required by the page editor are filled even when the model permits
blank values, without changing the model's field definitions.
It uses Wagtail's allowed parent/child models, can_create_at(), global max_count
and per-parent limits. Titles come from model names: NewsOverviewPage becomes
seed-News Overview. Generated text uses readable page/block and field names,
for example seed-Hero-Title, with sample paragraphs for longer text. Unique values
only receive an extra suffix when needed, including uniqueness within a locale.
Valid defaults and populated content are retained, including
visibility flags, locales, translation keys and configured values.
PAGE_COUNTS maps model labels to positive counts per public tree and locale;
the default is one of each applicable concrete type. A subclass does not count as
its parent type. Wagtail's global singleton limits still take precedence.
UNIQUE_PAGE_SCOPES adds post-seed checks for combinations of site, region
and/or language.
Stream/List blocks and InlinePanels follow their minimum/maximum counts, including
nested block_counts. By default, streams contain a compact representative sample.
Enable Alle bloktypen vullen in the dashboard, pass --all-block-types to
seed_wagtail or seed_wagtail_pages, or use Seeder(all_block_types=True) to try
every available block type, including nested streams and streams inside lists.
Existing blocks are retained and missing types are added when space permits.
Configured providers and protected field values remain authoritative. Excluded,
unsupported or capacity-limited types are reported; mandatory content must still
validate. This does not generate a separate block for each dropdown choice.
REQUIRED_STREAMFIELD_ITEM_COUNTS supplies additional
business constraints not declared on the block:
"REQUIRED_STREAMFIELD_ITEM_COUNTS": {"pages.ArticlePage.highlights": 2}
SNIPPET_COUNTS accepts model labels or legacy class names (labels take precedence).
The default is four; use zero to request no new instances. Translatable snippets
are generated for every configured root locale. Existing instances are reused and
validated, and stale chooser links are repaired without replacing their text.
Site settings are populated before saving, then revisited after their hooks have
created any additional pages. Page-owned inlines keep their original parent.
When wagtailstreamforms is installed, the seeder builds local contact forms from
registered single-line, email and multiline field blocks and configured templates.
It also supports older installations with separate FormField models. Submission
hooks stay empty; the seeder does not submit forms or send mail.
The inspector only reads configuration and model structure; it does not execute
model validation or prove rendering works. seed_wagtail --require-complete checks
both that graph and the results of actual model/block validation. Missing mandatory
content fails the command. Optional unsupported blocks/inlines are reported as
skipped; declared exclusions are intentional. Failed objects are rolled back,
while successful objects remain available for diagnosis.
Small project providers
Use providers for business rules that cannot be inferred from field declarations. Keep them in the consuming project and configure dotted paths:
"MODEL_VALUE_PROVIDERS": ["myproject.seeding.model_values"],
"FIELD_VALUE_PROVIDERS": ["myproject.seeding.field_values"],
"BLOCK_VALUE_PROVIDERS": ["myproject.seeding.block_values"],
Model providers receive (instance, context) during prepare (before generic
population) and validate (before validation). Make them idempotent. Field providers
receive (instance, field, context) during pre/post, including relation and
StreamField fields. Block providers receive (block, context). Field and block
providers return wagtail_seeder.providers.UNHANDLED to delegate generation;
returning None intentionally supplies an empty value.
Context includes seeder, config, scoped pages, phase, instance/owner,
site, locale, a zero-based index, field_name and a tuple block_path.
For model providers, index is stable within the model's ordered instances and
locale scope. For nested block providers it identifies the current stream/list item.
Protected field_values bypass generic field generation and link repair; model
providers may deliberately change them.
For example, a project that retrieves exactly one navigation object per language
can assign the configured languages using the model provider's index. Match
SNIPPET_COUNTS to the number of languages. See the
configuration guide for generic examples covering multiple
sites, custom validation, technical page types and external dependencies.
External integrations
Exclude models and blocks whose validation or rendering needs an external service:
"EXCLUDED_SNIPPET_MODELS": ["newsletter.MailingList"],
"SKIP_BLOCK_CLASS_NAMES": {"NewsletterBlock": "requires an external service"},
Exclusions also apply to indirect chooser/required-relation creation. Block exclusions match class names, qualified names and subclasses. A required excluded dependency is an error; a provider or a different valid local block is needed. External optional video URL fields with empty valid defaults stay empty. Seeder settings cannot turn off network calls hardcoded in a project's page rendering or save hooks.
Other optional keys are ALLOWED_ENVIRONMENTS (default {"dev"}),
ALLOWED_HOSTNAMES (dashboard request guard), FAKER_LOCALE (default "nl_NL"),
DEFAULT_SITE_HOSTNAME (default "localhost") and DEFAULT_SITE_PORT
(default 8000). Complete local compatibility requires testing the generated
frontend and editor in the consuming project; static inspection cannot guarantee
arbitrary custom validation or JavaScript behavior.
Development and testing
The repository separates the distributable package from its local test project:
src/wagtail_seeder/ Python package, management commands and admin templates
tests/test_project/ Runnable Django/Wagtail project, local database and media
tests/models.py Example page and relation models
tests/migrations/ One initial migration for the example models
tests/test_*.py Automated tests
From the repository root, create an environment and install the package in editable
mode. Changes in src then take effect immediately:
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
pytest
The default installation uses the latest available Wagtail 7.x. To test the lowest
supported release series, use a separate environment and install with
python -m pip install -e ".[dev]" "wagtail>=7,<7.1".
Run the same checks as CI:
python tests/test_project/manage.py check
python tests/test_project/manage.py makemigrations --check --dry-run
ruff check .
ruff format --check .
pytest
Automated tests use an isolated database and temporary media directories. They do not change the local demo database or leave generated media in the repository root.
Local Wagtail project
No external project or Bakery Demo checkout is required. From the repository root:
python tests/test_project/manage.py migrate
python tests/test_project/manage.py createsuperuser
python tests/test_project/manage.py inspect_wagtail_seed --require-complete
python tests/test_project/manage.py seed_wagtail --confirm --require-complete
python tests/test_project/manage.py runserver
Open http://127.0.0.1:8000/admin/ and log in. Explicitly assign Can run Wagtail
Seeder to the account or its group before opening Seeder in the menu.
Visit http://127.0.0.1:8000/admin/seeder/ to test a full seed or
selected page types. The confirmation checkbox is required for a destructive full
seed. Open http://127.0.0.1:8000/ to browse the generated pages.
For example, test the selective command with:
python tests/test_project/manage.py seed_wagtail_pages --page-type tests.ArticlePage
The local database, uploaded/generated media and collected static files live under
tests/test_project/ and are ignored by Git. The project is configured for local
development only.
The example models use one initial migration. If a local demo database was created
with the previous migration layout, recreate that demo database before migrating.
Installed packages continue to use the separate wagtail_seeder permission migration.
Building and releasing
Build the wheel and source distribution and check their metadata:
python -m build
python -m twine check dist/*
python scripts/check_distribution.py
tar -tf dist/wagtail_seeder-*.tar.gz
unzip -l dist/wagtail_seeder-*.whl
Before publishing, install the built wheel in the target project's environment
with python -m pip install /path/to/wagtail_seeder-1.0.0-py3-none-any.whl, then
apply migrations and the local Seeder configuration. Check a full seed, selective
seeding, frontend rendering and saving generated pages in the editor. This tests
the packaged assets and any custom validation in the application.
Runtime code and templates come from src/wagtail_seeder/. Tests, demo databases
and media are excluded from both distributions. The source archive also contains
the README, license and build metadata.
Public releases are published from GitLab CI to PyPI using Trusted Publishing. Before the first release, configure a pending publisher on PyPI (or a publisher on the existing project) with:
- PyPI project:
wagtail-seeder - GitLab namespace:
fourdigits/private-packages - GitLab project:
wagtail-seeder - Pipeline file:
.gitlab-ci.yml - Environment:
pypi
Protect the v* tag pattern in GitLab. No stored PyPI API token is needed.
Update the version in the project metadata and
src/wagtail_seeder/__init__.py, then push a protected tag matching that version,
for example v1.0.0. CI requires the tag and both version declarations to agree,
and publishes only after tests and package checks pass. Published versions cannot
be overwritten; bump the version for each new release.
License
BSD-3-Clause. See LICENSE.
Metadata
Release files for wagtail-seeder 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| wagtail_seeder-1.1.0.tar.gz | 48.0 kB | Without provenance | Details for wagtail_seeder-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| wagtail_seeder-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for wagtail_seeder-1.1.0-py3-none-any.whl |
Total release size: 92.8 kB
Release files / wagtail_seeder-1.1.0.tar.gz
| Download URL | wagtail_seeder-1.1.0.tar.gz |
|---|---|
| Size | 48.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8dd94b518ccaac6ecb2dde3e637df6c90284d6daeefea949a7c49bb0a4dec0e3
|
|
BLAKE2b-256 checksum How to use checksums |
060094a5032ddc9459ea741382d3fa426e4a17fc7a8bd89fe5cab9076159667e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / wagtail_seeder-1.1.0-py3-none-any.whl
| Download URL | wagtail_seeder-1.1.0-py3-none-any.whl |
|---|---|
| Size | 44.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3eae102dcdef2e9341999f16f3a7b3604b4fb426893cabc43b61dca0ba40730c
|
|
BLAKE2b-256 checksum How to use checksums |
55103f56aa701c34d612239eb04da1bec9504223b113ed398cb47467d2039ef9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Security for wagtail-seeder 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.