如何将页面隐私复制到 Wagtail 中的 Block?

How to copy page-privacy to Block in Wagtail?

页面具有此隐私设置,可以设置允许哪些人查看特定页面。

我的文档需要更精细的杠杆,对于特定的块,还可以设置为限制其可见性。

我对组选择器非常满意,但显然我不能在 Page 模型中放置 ManyToManyRelation。相反,我会在我需要特别处理的块中进行。

所以我尝试像这样定义块:

class MyBlock(StructBlock):
    visible_groups = ListBlock(ChooserBlock(
        label=_('Limit view to groups'), target_model='django.contrib.auth.groups', 
        required=False, blank=True
    ))

但是 Wagtail 抱怨说 ChooserBlock 的声明没有 target_model 属性。我想缺少构造函数就足以表明 ChooserBlock 本身不适用于这样的操作。

我如何正确声明我的块,以便我可以 select 组,然后在渲染时正确识别它们并将它们与用户组匹配?

ChooserBlock 不能单独使用,而是一个基础 class 可以用来构建其他类型的选择器。

选项 0 - 使用相关模型

  • 虽然我理解您不想使用模型关系的愿望,但您可能会通过尝试在此处使用 StreamFields 最终造成很多复杂性。
  • 可能值得根据基本关系重新考虑问题,您的页面作为内容项列表,每个内容项与授权组具有一对多关系并且具有一些内容(富文本等) .
  • 您可以使用与您的页面相关的普通模型来执行此操作,并使用 Wagtail 的 InlinePanel 允许用户创建许多这样的内容项,每个项都有自己的身份验证组集和内容。请记住,其他模型的内部内容仍然可以基于 StreamField,但此方法中的主要连接将是正常的 Django 关系。
  • 请记住,StreamField 链接不那么可靠(例如,如果 auth 组被删除,链接可能会在您的 StreamField 中变得陈旧,并且没有简单的方法来阻止它),而且如果您想移动,迁移会变得非常复杂以后身边的事情多一些。

选项 1 - 使用 SnippetChooser

实现此功能的最快方法是使用 SnippetChooserBlock and register the Django auth groups as a snippet。这种方法的一个警告是模型将在管理员的代码片段菜单(如果启用)中可见 UI。

首先,将模型注册为中心某处的片段(例如wagtail_hooks.py

from django.contrib.auth.models import Group
from wagtail.snippets.models import register_snippet

# ... other hooks things
register_snippet(Group)

然后使用 SnippetChooser 构建您的自定义 StructBlock,无论您在哪里放置积木。

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"

最后,您可以像使用任何其他 StructBlock 一样在您的 PageModel 中使用它。

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'),
    ]

选项 2 - 构建或使用通用模型选择

您可以扩展 ChooserBlock 来构建您自己的选择器,但这很快就会变得复杂,因为您还需要构建自定义模型选择器。下面的代码功能不全,但可以让您了解可能需要什么。

如果您可以使用其他库,可能值得考虑添加 Wagtail 通用选择器,这里是 Google 的一些快速结果(我没有使用过这些)。

请记住,选择器块特定于 StreamField 实现,选择器类似于特定类型的 Django 小部件。如果要为此实现使用 StreamFields,则需要构建或获取两者。

如果您需要构建自己的选择器,我建议您深入了解 Wagtail 的内部结构,了解其他选择器的构建方式。

POC(非功能性)代码示例


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"