No way to specify default values for StreamBlockFactory



This is a pre-emptive issue ahead of the merge of #55 to document a missing feature without unnecessarily holding up that PR. The PR adds a new StreamBlockFactory class that can be passed as the argument to a StreamFieldFactory declaration. The missing feature is the ability to specify the default value of a StreamBlockFactory subclass, either when it's passed to StreamFieldFactory or on the class definition itself.

The relationship between StreamFieldFactory and StreamBlockFactory is a bit like the relationship between SubFactory and Factory, so it'd be nice to be able to do something similar to the **kwargs that SubFactory.__call__ accepts to set the default value of the generated stream data. However, the values will always start with block indexes (e.g. 0__my_block_type__some_attribute="foo") which aren't legal Python kwarg names, so my proposal for this API would be to accept an optional dict-like object that defines the defaults, something like:

class MyPageFactory(wagtail_factories.PageFactory):
  body = wagtail_factories.StreamFieldFactory(
      "0": "my_block_type",  # Default value for "my_block_type"
      "1__my_block_type__some_field": "foo",  # Explicit value for a nested field

The above should work well for defining default data for a given use of a StreamBlockFactory, it would also be useful to be able to specify default values as part of the StreamBlockFactory definition as well, so that the same data could be used in multiple places without being redefined. I'm less sure how the API for this should look, but one idea might be adding a new default_data member to the Meta class, something like this:

class MyStreamBlockFactory(wagtail_factories.StreamBlockFactory):
  my_block_type = factory.SubFactory(MyBlockTypeFactory)

  class Meta:
    model = MyStreamBlock
    default_data = {
      "0": "my_block_type",  # Default value for "my_block_type"
      "1__my_block_type__some_field": "foo",  # Explicit value for a nested field
2022-07-13 16:14:31

Add a Comment

Top 3 Comments

  jams2 answered on 2022-07-18 14:18:29


I am confused by the "0": "my_block_type", # Default value for "my_block_type". Is "0" the value?

In this case, this means that the 0th item in the generated StreamValue would get the default value for the my_block_type declaration - in this case it will be the default value of MyBlockTypeFactory.

@bcdickinson it might be worth changing StreamFieldFactory so it is a SubFactory subclass - that way one could provide a defaults dict in the declaration. From a high level this wouldn't be too difficult.

To allow specifying StreamBlockFactory defaults on the Meta class, I think we'd have to further extend StreamBlockStepBuilder. One way would be to update its __init__ method to merge extras and factory_meta.default_data before doing the work that generates the actual factory class that's used for object generation.

Question: given a StreamBlockFactory definition like this:

class BodyFactory(StreamBlockFactory):
    struct_1 = SubFactory(Struct1Factory)
    struct_2 = SubFactory(Struct2Factory)

    class Meta:
        default_data = {"0": "struct_1", "1": "struct_1"}

and a call like MyPageFactory(body__1="struct_2"), would you expect the declarations to be merged such that you effectively end up generating data from

    "0": "struct_1",  # from meta.default_data,
    "1": "struct_2",  # from extras at page factory instantiation


0 positive reactions.
  tbrlpld answered on 2022-07-15 15:02:44

If the issue we are trying to solve is the fact that the block "descriptor" (not sure what to call it) starts with a number (because we don't know the name of the field on the parent), could we just use something generic as the start for the string like "self__0__my_block_type__some_field": ...?

0 positive reactions.
  tbrlpld answered on 2022-07-15 14:37:11

@bcdickinson I am confused by the "0": "my_block_type", # Default value for "my_block_type". Is "0" the value?

0 positive reactions.

Quick Hint

What do GREY wagtails like to eat?

Grey wagtails eat ants and midges that they find beside rivers, and snails and tadpoles they find in shallow water. They nest near the water in hollows and crevices lined with moss and twigs.

Repo Information

Age 5yrs
Vendor wagtail
Repo Name wagtail-factories
Primary Language Python
Default Branch main
Last Update 4 months ago

Wagtail's Code Library

Similar Issues

πŸ’Ύ wagtail Add ActivityPub support πŸ’¬ 5 closed πŸ—“οΈ 5 days ago
πŸ’Ύ wagtail Page jumps to top on "save draft" πŸ’¬ 3 open πŸ—“οΈ 1 week ago
πŸ’Ύ wagtail Eslint cleanup no plusplus rule πŸ’¬ 5 closed πŸ—“οΈ 1 week ago
πŸ’Ύ Performance: Enable text compression πŸ’¬ 3 closed πŸ—“οΈ 2 weeks ago
πŸ’Ύ Performance: serve images in next-gen formats πŸ’¬ 4 closed πŸ—“οΈ 2 weeks ago
πŸ’Ύ wagtail Local setup Error for Safari Browser πŸ’¬ 3 open πŸ—“οΈ 2 weeks ago
πŸ’Ύ wagtail Clean up eslint usage `no-prototype-builtins` πŸ’¬ 7 closed πŸ—“οΈ 3 weeks ago