ChooserBlock
is not meant to be used stand-alone, instead it is a base class that is meant to be used to build up other types of chooser.
Option 0 - Use a related model
- While I understand your desire not to use a model relationship, you might end up creating a lot of complexity by attempting to use StreamFields here.
- It might be worthwhile rethinking the problem in terms of basic relationships, your page as a list of content items, each content item has a one to many relationship to an auth group AND has some content (rich text, etc).
- You could do this with a normal model that relates to your page, and using Wagtail's InlinePanel allow the user to create many of these content items each with its own auth group set AND content. Remember the inner content on other models can still be StreamField based but the main connections in this method would be normal Django relationships.
- Remember that StreamField links are not as robust (e.g. if auth groups get deleted, the links may become stale in your StreamField and there are no easy ways to block this), plus migrations become quite complicated if you want to move things around more in the future.
Option 1 - Use SnippetChooser
The quickest way to get this working would be to use the SnippetChooserBlock
and register the Django auth groups as a snippet. One caveat to this approach is that the model will be visible in your snippets menu (if enabled) in the admin UI.
Firstly, register the model as a snippet somewhere central (e.g. wagtail_hooks.py
)
from django.contrib.auth.models import Group
from wagtail.snippets.models import register_snippet
# ... other hooks things
register_snippet(Group)
Then build your custom StructBlock
using the SnippetChooser
wherever you keep your Blocks.
from django.contrib.auth.models import Group
from wagtail.snippets.blocks import SnippetChooserBlock
from wagtail.core.blocks import ListBlock
class PrivacyBlock(StructBlock):
visible_groups = ListBlock(
SnippetChooserBlock(
Group,
label='Limit view to groups',
required=False,
blank=True
)
)
class Meta:
icon = "user"
Finally, you can use this in your PageModel like any other StructBlock.
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, StreamFieldPanel
from wagtail.core.fields import StreamField
from myapp.blocks import PrivacyBlock
class BlogPage(Page):
# ... other fields
privacy_content = StreamField([
('privacy', PrivacyBlock(blank=True))
])
content_panels = Page.content_panels + [
# ... other panels
StreamFieldPanel('privacy_content'),
]
Option 2 - Build or use a generic model choose
You can extend the ChooserBlock to build your own chooser, but this gets complicated quickly as you need to also build a custom model chooser. The code below is NOT fully function but gives you an idea of what might be needed.
If you can use additional libraries, it might be worth looking into adding a Wagtail Generic Chooser, here are some quick results from Google (I have not used these).
Remember that a chooser block is specific to StreamField implementations and chooser akin to a specific type of Django widget. You will need to build or get both if you want to use StreamFields for this implementation.
If you need to build your own I recommend to dig into the Wagtail internals to get an idea of how some other choosers are built.
POC (non functional) code example
from wagtail.admin.widgets import AdminChooser
from django.utils.functional import cached_property
class ModelChooser(AdminChooser):
# ... implement __init__ etc
class AuthGroupBlock(ChooserBlock):
@cached_property
def target_model(self):
from django.contrib.auth.models import Group
return Group
@cached_property
def widget(self):
return ModelChooser(self.target_model)
class PrivacyBlock(StructBlock):
visible_groups = ListBlock(
AuthGroupBlock(
label='Limit view to groups',
required=False,
blank=True
)
)
class Meta:
icon = "user"
class PrivacyBlock(StructBlock):
visible_groups = ListBlock(
SnippetChooserBlock(
Group,
label='Limit view to groups',
required=False,
blank=True
)
)
class Meta:
icon = "user"