# wagtail-factories
Factory boy classes for Wagtail CMS
## Installation
``` shell
pip install wagtail-factories
```
## Usage
Documentation is still in progress, but see the
[tests](https://github.com/wagtail/wagtail-factories/tree/main/tests)
for more examples.
``` python
import wagtail_factories
from . import models
class MyCarouselItemFactory(wagtail_factories.StructBlockFactory):
label = 'my-label'
image = factory.SubFactory(
wagtail_factories.ImageChooserBlockFactory)
class Meta:
model = models.MyBlockItem
class MyCarouselFactory(wagtail_factories.StructBlockFactory):
title = "Carousel title"
items = wagtail_factories.ListBlockFactory(
MyCarouselItemFactory)
class Meta:
model = models.MyCarousel
class MyNewsPageFactory(wagtail_factories.PageFactory):
class Meta:
model = models.MyNewsPage
class MyNewsPageChooserBlockFactory(wagtail_factories.PageChooserBlockFactory):
page = factory.SubFactory(MyNewsPageFactory)
class MyTestPageFactory(wagtail_factories.PageFactory):
body = wagtail_factories.StreamFieldFactory({
'carousel': factory.SubFactory(MyCarouselFactory),
'news_page': factory.SubFactory(MyNewsPageChooserBlockFactory),
})
class Meta:
model = models.MyTestPage
def test_my_page():
root_page = wagtail_factories.PageFactory(parent=None)
my_page = MyTestPageFactory(
parent=root_page,
body__0__carousel__items__0__label='Slide 1',
body__0__carousel__items__0__image__image__title='Image Slide 1',
body__0__carousel__items__1__label='Slide 2',
body__0__carousel__items__1__image__image__title='Image Slide 2',
body__0__carousel__items__2__label='Slide 3',
body__0__carousel__items__2__image__image__title='Image Slide 3',
body__1__news_page__page__title="News",
)
```
### Using StreamBlockFactory
`StreamBlockFactory` can be used in conjunction with the other block
factory types to create complex, nested `StreamValues`, much like how
`StreamBlock` can be used to declare the blocks for a complex
`StreamField`.
First, define your `StreamBlockFactory` subclass, using
`factory.SubFactory` to wrap child block declarations. Be sure to
include your `StreamBlock` subclass as the model attribute on the inner
`Meta` class.
``` python
class MyStreamBlockFactory(wagtail_factories.StreamBlockFactory):
my_struct_block = factory.SubFactory(MyStructBlockFactory)
class Meta:
model = MyStreamBlock
```
Then include your `StreamBlockFactory` subclass on a model factory as
the argument to a `StreamFieldFactory`.
``` python
class MyPageFactory(wagtail_factories.PageFactory):
body = wagtail_factories.StreamFieldFactory(MyStreamBlockFactory)
class Meta:
model = MyPage
```
You can then use a modified version of factory\_boy\'s deep object
declaration syntax to build up `StreamValues` on the fly.
``` python
MyPageFactory(
body__0__my_struct_block__some_field="some value",
body__0__my_struct_block__some_other_field="some other value",
)
```
To generate the default value for a block factory, terminate your
declaration at the index and provide the block name as the value.
``` python
MyPageFactory(body__0="my_struct_block")
```
### Alternative StreamFieldFactory declaration syntax
Prior to version 3.0, `StreamFieldFactory` could only be used by
providing a dict mapping block names to block factory classes as the
single argument, for example:
``` python
class MyTestPageWithStreamFieldFactory(wagtail_factories.PageFactory):
body = wagtail_factories.StreamFieldFactory(
{
"char_array": wagtail_factories.ListBlockFactory(
wagtail_factories.CharBlockFactory
),
"int_array": wagtail_factories.ListBlockFactory(
wagtail_factories.IntegerBlockFactory
),
"struct": MyBlockFactory,
"image": wagtail_factories.ImageChooserBlockFactory,
}
)
class Meta:
model = models.MyTestPage
```
This style of declaration is still supported, with the caveat that
nested stream blocks are not supported for this approach. From version
3.0, all `BlockFactory` values in a `StreamFieldFactory` definition of
this style *must* be wrapped in factory\_boy `SubFactories`. For
example, the above example must be updated to the following for 3.0
compatibility.
``` python
class MyTestPageWithStreamFieldFactory(wagtail_factories.PageFactory):
body = wagtail_factories.StreamFieldFactory(
{
"char_array": wagtail_factories.ListBlockFactory(
wagtail_factories.CharBlockFactory
),
"int_array": wagtail_factories.ListBlockFactory(
wagtail_factories.IntegerBlockFactory
),
"struct": factory.SubFactory(MyBlockFactory),
"image": factory.SubFactory(wagtail_factories.ImageChooserBlockFactory),
}
)
class Meta:
model = models.MyTestPage
```
This requirement does *not* apply to `ListBlockFactory`, which is a
subclass of `SubFactory`.
Raw data
{
"_id": null,
"home_page": "https://github.com/wagtail/wagtail-factories/",
"name": "wagtail-factories",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "Michael van Tellingen",
"author_email": "michaelvantellingen@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/cb/0f/f00ce36a1eaea91075817c65c0c4f6644dc20138e397aafd89afe2e2c3e3/wagtail_factories-4.3.0.tar.gz",
"platform": null,
"description": "# wagtail-factories\n\nFactory boy classes for Wagtail CMS\n\n## Installation\n\n``` shell\npip install wagtail-factories\n```\n\n## Usage\n\nDocumentation is still in progress, but see the\n[tests](https://github.com/wagtail/wagtail-factories/tree/main/tests)\nfor more examples.\n\n``` python\nimport wagtail_factories\nfrom . import models\n\n\nclass MyCarouselItemFactory(wagtail_factories.StructBlockFactory):\n label = 'my-label'\n image = factory.SubFactory(\n wagtail_factories.ImageChooserBlockFactory)\n\n class Meta:\n model = models.MyBlockItem\n\n\nclass MyCarouselFactory(wagtail_factories.StructBlockFactory):\n title = \"Carousel title\"\n items = wagtail_factories.ListBlockFactory(\n MyCarouselItemFactory)\n\n class Meta:\n model = models.MyCarousel\n\n\nclass MyNewsPageFactory(wagtail_factories.PageFactory):\n class Meta:\n model = models.MyNewsPage\n\n\nclass MyNewsPageChooserBlockFactory(wagtail_factories.PageChooserBlockFactory):\n page = factory.SubFactory(MyNewsPageFactory)\n\n\nclass MyTestPageFactory(wagtail_factories.PageFactory):\n body = wagtail_factories.StreamFieldFactory({\n 'carousel': factory.SubFactory(MyCarouselFactory),\n 'news_page': factory.SubFactory(MyNewsPageChooserBlockFactory),\n })\n\n class Meta:\n model = models.MyTestPage\n\n\ndef test_my_page():\n root_page = wagtail_factories.PageFactory(parent=None)\n my_page = MyTestPageFactory(\n parent=root_page,\n body__0__carousel__items__0__label='Slide 1',\n body__0__carousel__items__0__image__image__title='Image Slide 1',\n body__0__carousel__items__1__label='Slide 2',\n body__0__carousel__items__1__image__image__title='Image Slide 2',\n body__0__carousel__items__2__label='Slide 3',\n body__0__carousel__items__2__image__image__title='Image Slide 3',\n body__1__news_page__page__title=\"News\",\n )\n```\n\n### Using StreamBlockFactory\n\n`StreamBlockFactory` can be used in conjunction with the other block\nfactory types to create complex, nested `StreamValues`, much like how\n`StreamBlock` can be used to declare the blocks for a complex\n`StreamField`.\n\nFirst, define your `StreamBlockFactory` subclass, using\n`factory.SubFactory` to wrap child block declarations. Be sure to\ninclude your `StreamBlock` subclass as the model attribute on the inner\n`Meta` class.\n\n``` python\nclass MyStreamBlockFactory(wagtail_factories.StreamBlockFactory):\n my_struct_block = factory.SubFactory(MyStructBlockFactory)\n\n class Meta:\n model = MyStreamBlock\n```\n\nThen include your `StreamBlockFactory` subclass on a model factory as\nthe argument to a `StreamFieldFactory`.\n\n``` python\nclass MyPageFactory(wagtail_factories.PageFactory):\n body = wagtail_factories.StreamFieldFactory(MyStreamBlockFactory)\n\n class Meta:\n model = MyPage\n```\n\nYou can then use a modified version of factory\\_boy\\'s deep object\ndeclaration syntax to build up `StreamValues` on the fly.\n\n``` python\nMyPageFactory(\n body__0__my_struct_block__some_field=\"some value\",\n body__0__my_struct_block__some_other_field=\"some other value\",\n)\n```\n\nTo generate the default value for a block factory, terminate your\ndeclaration at the index and provide the block name as the value.\n\n``` python\nMyPageFactory(body__0=\"my_struct_block\")\n```\n\n### Alternative StreamFieldFactory declaration syntax\n\nPrior to version 3.0, `StreamFieldFactory` could only be used by\nproviding a dict mapping block names to block factory classes as the\nsingle argument, for example:\n\n``` python\nclass MyTestPageWithStreamFieldFactory(wagtail_factories.PageFactory):\n body = wagtail_factories.StreamFieldFactory(\n {\n \"char_array\": wagtail_factories.ListBlockFactory(\n wagtail_factories.CharBlockFactory\n ),\n \"int_array\": wagtail_factories.ListBlockFactory(\n wagtail_factories.IntegerBlockFactory\n ),\n \"struct\": MyBlockFactory,\n \"image\": wagtail_factories.ImageChooserBlockFactory,\n }\n )\n\n class Meta:\n model = models.MyTestPage\n```\n\nThis style of declaration is still supported, with the caveat that\nnested stream blocks are not supported for this approach. From version\n3.0, all `BlockFactory` values in a `StreamFieldFactory` definition of\nthis style *must* be wrapped in factory\\_boy `SubFactories`. For\nexample, the above example must be updated to the following for 3.0\ncompatibility.\n\n``` python\nclass MyTestPageWithStreamFieldFactory(wagtail_factories.PageFactory):\n body = wagtail_factories.StreamFieldFactory(\n {\n \"char_array\": wagtail_factories.ListBlockFactory(\n wagtail_factories.CharBlockFactory\n ),\n \"int_array\": wagtail_factories.ListBlockFactory(\n wagtail_factories.IntegerBlockFactory\n ),\n \"struct\": factory.SubFactory(MyBlockFactory),\n \"image\": factory.SubFactory(wagtail_factories.ImageChooserBlockFactory),\n }\n )\n\n class Meta:\n model = models.MyTestPage\n```\n\nThis requirement does *not* apply to `ListBlockFactory`, which is a\nsubclass of `SubFactory`.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Factory boy classes for wagtail",
"version": "4.3.0",
"project_urls": {
"Homepage": "https://github.com/wagtail/wagtail-factories/"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "2e5cdc0bcc00512d27423e3bb2b4eee44f3bcbd1c1569910d01d17b6e0e0cc27",
"md5": "9152b0d075d342dcff002ed6c17330fa",
"sha256": "6d3129244642a400462344e35168e5eb89598d5b63a4cfb7f26a5a6052f50d95"
},
"downloads": -1,
"filename": "wagtail_factories-4.3.0-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "9152b0d075d342dcff002ed6c17330fa",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 10513,
"upload_time": "2025-08-15T08:49:45",
"upload_time_iso_8601": "2025-08-15T08:49:45.549256Z",
"url": "https://files.pythonhosted.org/packages/2e/5c/dc0bcc00512d27423e3bb2b4eee44f3bcbd1c1569910d01d17b6e0e0cc27/wagtail_factories-4.3.0-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "cb0ff00ce36a1eaea91075817c65c0c4f6644dc20138e397aafd89afe2e2c3e3",
"md5": "dfcbdba4cc1b6dfaf0587a3e16127fcc",
"sha256": "27c19078ceade5e408aef0edfa3378b7992e5bed4d4c7e8216cbdd53f9732464"
},
"downloads": -1,
"filename": "wagtail_factories-4.3.0.tar.gz",
"has_sig": false,
"md5_digest": "dfcbdba4cc1b6dfaf0587a3e16127fcc",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 9613,
"upload_time": "2025-08-15T08:49:46",
"upload_time_iso_8601": "2025-08-15T08:49:46.400361Z",
"url": "https://files.pythonhosted.org/packages/cb/0f/f00ce36a1eaea91075817c65c0c4f6644dc20138e397aafd89afe2e2c3e3/wagtail_factories-4.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-15 08:49:46",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "wagtail",
"github_project": "wagtail-factories",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "wagtail-factories"
}