Reputation: 10025
Pages have this privacy setting where one can set who is allowed to see a particular page.
My documentation requires a bit more granular lever where for a specific block one could also set to restrict its visibility.
I would be quite content with a groups chooser, but obviously I can't place a ManyToManyRelation in the Page model. Rather I would do it in the Block I need specially handled.
So I tried to define the block like so:
class MyBlock(StructBlock):
visible_groups = ListBlock(ChooserBlock(
label=_('Limit view to groups'), target_model='django.contrib.auth.groups',
required=False, blank=True
))
But Wagtail complains that ChooserBlock had been declared without target_model attribute. I guess lack of constructor doing so is an indicator enough that ChooserBlock itself is not meant for operations like this.
How could I properly declare my Block such that I could select the groups and then later - while rendering - correctly identify them and match them against user's groups?
Upvotes: 0
Views: 309
Reputation: 5186
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.
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'),
]
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"
Upvotes: 2