8000 Allow `Block.preview_value` to be a callable · Issue #13094 · wagtail/wagtail · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Allow Block.preview_value to be a callable #13094

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
laymonage opened this issue May 7, 2025 · 0 comments
Open

Allow Block.preview_value to be a callable #13094

laymonage opened this issue May 7, 2025 · 0 comments

Comments

@laymonage
Copy link
Member

Is your proposal related to a problem?

When defining the preview value for StreamField blocks to be used in the block previews, you only have the following options:

  • Set preview_value on the block's Meta class
  • Pass preview_value when instantiating the block
  • Subclass the block and override get_preview_value()

The first two options are "eager", i.e. the value needs to be evaluated at startup time. This makes them unsuitable for values that require database access, e.g. chooser blocks like ImageBlock and DocumentChooserBlock. The last option requires subclassing the block. If you have multiple instances of the chooser blocks in different context, having to subclass each block class in order to have a different preview value is not very friendly.

Describe the solution you'd like

The default implementation of Block.get_preview_value() should allow self.meta.preview_value to be a callable with no arguments, in similar vein to Django's model fields default option. In fact, perhaps it's good to also tackle #7992 as part of this. This can be done by checking for callable() in get_preview_value() and get_default() and calling the value if it is indeed callable.

def get_preview_value(self):
"""
Return the placeholder value that will be used for rendering the block's
preview. By default, the value is the ``preview_value`` from the block's
options if provided, otherwise the ``default`` is used as fallback. This
method can be overridden to provide a dynamic preview value, such as
from the database.
"""
if hasattr(self.meta, "preview_value"):
return self.normalize(self.meta.preview_value)
return self.get_default()

def get_default(self):
"""
Return this block's default value (conventionally found in self.meta.default),
converted to the value type expected by this block. This caters for the case
where that value type is not something that can be expressed statically at
model definition time (e.g. something like StructValue which incorporates a
pointer back to the block definition object).
"""
return self.normalize(getattr(self.meta, "default", None))

Describe alternatives you've considered

If #7992 is handled, this feature would already be possible by proxy (i.e. by defining a callable default and not defining a preview_value). However, it's still nice to have in case you want the preview value to be different from the default value (or have no default value at all).

Additional context

We'll also need new test cases in the following test:

def test_preview_value(self):
class PreviewValueViaMeta(blocks.Block):
class Meta:
preview_value = "Hello, world!"
class PreviewValueViaMethod(blocks.Block):
def get_preview_value(self):
return "Hello, world!"
cases = [
("meta", PreviewValueViaMeta()),
("method", PreviewValueViaMethod()),
("kwarg", blocks.Block(preview_value="Hello, world!")),
("localized", blocks.Block(preview_value=_("Hello, world!"))),
(
"localized_rich_text",
blocks.RichTextBlock(preview_value=_("<p>Hello, world!</p>")),
),
]
for via, block in cases:
with self.subTest(via=via):
response = self.get(block)
self.assertEqual(response.status_code, 200)
soup = self.get_soup(response.content)
main = soup.select_one("main")
self.assertIsNotNone(main)
self.assertEqual(main.text.strip(), "Hello, world!")

Working on this

Anyone can contribute to this. View our contributing guidelines, add a comment to the issue once you’re ready to start.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant
0