将 link 可用的页面过滤到另一个页面
Filter the pages available to link to another page
我真的是 Wagtail 的新手。我一直在尝试寻找一种方法来过滤选择器 (PageChooserPanel) 中的值。我正在构建一个故事站点,作者可以在其中创建非线性故事。我遵循博客模型来构建它并对其进行扩展。我已经到了作者可以通过订购 link 翻页的地步。问题是可订购的显示其他故事的页面。有没有办法过滤掉不相关的页面。我很感激这方面的任何帮助。提前致谢!
这是我的代码:
class StoryPath(models.Model):
route = models.ForeignKey('story.StoryPage', on_delete=models.SET_NULL, null=True, related_name='next_path', verbose_name='Story Path')
panels = [
PageChooserPanel('route', page_type='story.StoryPage'),
FieldPanel('correct'),
]
class Meta:
abstract = True
class StoryPathOrderable(Orderable, StoryPath):
page = ParentalKey('story.StoryPage', on_delete=models.CASCADE, related_name='story_paths')
class StoryPage(Page):
template = 'story/story_page.html'
body = RichTextField()
content_panels = [
FieldPanel('title', heading='Section Title', classname='collapsible'),
FieldPanel('body', classname='collapsible'),
MultiFieldPanel(
[
InlinePanel('story_paths'),
],
heading = 'Story Paths',
classname = 'collapsible'
)
]
parent_page_type =['story.Story']
subpage_types = []
def __str__(self):
return '%s' % (self.title)
class Story(Page):
subtitle = models.CharField(max_length=250, null=True, blank=True)
content_panels = Page.content_panels + [
FieldPanel('subtitle'),
]
subpage_types = ['story.StoryPage']
def __str__(self):
return '%s' % (self.title)
编辑:这是我正在使用的模板:
{% extends "base.html" %}
{% load static wagtailcore_tags %}
{% block body_class %}{{self.title}}{% endblock %}
{% block extra_css %}{% endblock extra_css %}
{% block content %}
<div class="d-flex justify-content-center flex-column">
<div class="fs-3">{{page.title}}</div>
<div>{{page.body|richtext}}</div>
</div>
{% endblock content %}
这对于 PageChooserPanel
来说并不容易,它会打开带有搜索界面的模式,但是如果您对字段只显示一个下降感到满意,那么您实现这个目标会容易得多下 'sibling' 页。
对这一切如何运作的一些概述;
- 当您使用
InlinePanel('story_paths'),
时,它会利用 Wagtail、Django 和 Django Modelcluster 的一些部分来设置动态表单集。
InlinePanel
允许您为类似对象的多次添加创建子 'forms',在这种情况下,内联创建的对象是 StoryPathOrderable
个实例。
- 当您使用
InlinePanel
时,它将在 created/managed 内联的内部模型上查找 panels
属性。
- 在您的内部模型上,您已设置
PageChooserPanel('route', page_type='story.StoryPage'),
。
PageChooserPanel
对于很多用例来说确实很棒,但对于边缘情况来说有点难以定制(因为它创建了一个字段来触发具有自己的 search/listing 界面的模式)。可以使用 Wagtail Hooks 修改此模式的结果 - 请参阅 `construct_page_chooser_queryset',但这是全局的,无法知道 'which' 页面或字段正在请求链接页面。
- 但是,我们不必使用
PageChooserPanel
,您可以使用基本的 FieldPanel
,它提供了整个应用程序可用页面的下拉列表,从那里我们可以自定义该字段的查询更简单。
- 如果您想对此进行更多控制并希望保留模态界面,您可以考虑使用 Wagtail Generic Chooser。
例子
- 下面我们将创建一个自定义
FieldPanel
来修改其 on_form_bound
的行为,一旦表单可用,就会在为编辑器构建表单时调用它。
- 从这里我们可以找到该页面列表字段的字段,并将其查询集修改为所需的结果。
page = self.page
将在您未使用 InlinePanel
时工作,因为实例将是当前编辑的页面。
- 但是,对于
InlinePanel
,我们需要考虑准备作为模板的 'initial' 表单的情况,以便您可以动态添加项目。
- 为了处理
InlinePanel
和基本字段的使用,我们可以获取绑定到自定义面板实例的当前请求,并从那里推断页面。
- 一旦我们有权访问
Page
和字段,我们就可以修改查询集以满足我们的需要,Wagtail 扩展了查询集的能力以添加 child_of
and sibling_of
.
some-app/models.py
from wagtail.admin.edit_handlers import FieldPanel
class SiblingOnlyPageFieldPanel(FieldPanel):
def on_form_bound(self):
super().on_form_bound()
field = self.form[self.field_name].field
# when creating a new page, check for the parent page ID & refine field queryset
parent_page_id = self.request.resolver_match.kwargs.get("parent_page_id", None)
if parent_page_id:
parent_page = Page.objects.filter(pk=parent_page_id).first()
field.queryset = field.queryset.child_of(parent_page)
return
# when editing a page, get the ID of the page currently being edited
page_id = self.request.resolver_match.kwargs.get("page_id", None)
if not page_id:
return
page = Page.objects.filter(pk=page_id).first()
if not page:
return
field = self.form[self.field_name].field
field.queryset = field.queryset.sibling_of(page)
class StoryPath(models.Model):
route = models.ForeignKey('story.StoryPage', on_delete=models.SET_NULL, null=True, related_name='next_path', verbose_name='Story Path')
panels = [
SibingOnlyPageFieldPanel('route'), # replaced PageChooserPanel & removed `page_type` as that will no longer work for a normal FieldPanel
FieldPanel('correct'),
]
class Meta:
abstract = True
我真的是 Wagtail 的新手。我一直在尝试寻找一种方法来过滤选择器 (PageChooserPanel) 中的值。我正在构建一个故事站点,作者可以在其中创建非线性故事。我遵循博客模型来构建它并对其进行扩展。我已经到了作者可以通过订购 link 翻页的地步。问题是可订购的显示其他故事的页面。有没有办法过滤掉不相关的页面。我很感激这方面的任何帮助。提前致谢!
这是我的代码:
class StoryPath(models.Model):
route = models.ForeignKey('story.StoryPage', on_delete=models.SET_NULL, null=True, related_name='next_path', verbose_name='Story Path')
panels = [
PageChooserPanel('route', page_type='story.StoryPage'),
FieldPanel('correct'),
]
class Meta:
abstract = True
class StoryPathOrderable(Orderable, StoryPath):
page = ParentalKey('story.StoryPage', on_delete=models.CASCADE, related_name='story_paths')
class StoryPage(Page):
template = 'story/story_page.html'
body = RichTextField()
content_panels = [
FieldPanel('title', heading='Section Title', classname='collapsible'),
FieldPanel('body', classname='collapsible'),
MultiFieldPanel(
[
InlinePanel('story_paths'),
],
heading = 'Story Paths',
classname = 'collapsible'
)
]
parent_page_type =['story.Story']
subpage_types = []
def __str__(self):
return '%s' % (self.title)
class Story(Page):
subtitle = models.CharField(max_length=250, null=True, blank=True)
content_panels = Page.content_panels + [
FieldPanel('subtitle'),
]
subpage_types = ['story.StoryPage']
def __str__(self):
return '%s' % (self.title)
编辑:这是我正在使用的模板:
{% extends "base.html" %}
{% load static wagtailcore_tags %}
{% block body_class %}{{self.title}}{% endblock %}
{% block extra_css %}{% endblock extra_css %}
{% block content %}
<div class="d-flex justify-content-center flex-column">
<div class="fs-3">{{page.title}}</div>
<div>{{page.body|richtext}}</div>
</div>
{% endblock content %}
这对于 PageChooserPanel
来说并不容易,它会打开带有搜索界面的模式,但是如果您对字段只显示一个下降感到满意,那么您实现这个目标会容易得多下 'sibling' 页。
对这一切如何运作的一些概述;
- 当您使用
InlinePanel('story_paths'),
时,它会利用 Wagtail、Django 和 Django Modelcluster 的一些部分来设置动态表单集。 InlinePanel
允许您为类似对象的多次添加创建子 'forms',在这种情况下,内联创建的对象是StoryPathOrderable
个实例。- 当您使用
InlinePanel
时,它将在 created/managed 内联的内部模型上查找panels
属性。 - 在您的内部模型上,您已设置
PageChooserPanel('route', page_type='story.StoryPage'),
。 PageChooserPanel
对于很多用例来说确实很棒,但对于边缘情况来说有点难以定制(因为它创建了一个字段来触发具有自己的 search/listing 界面的模式)。可以使用 Wagtail Hooks 修改此模式的结果 - 请参阅 `construct_page_chooser_queryset',但这是全局的,无法知道 'which' 页面或字段正在请求链接页面。- 但是,我们不必使用
PageChooserPanel
,您可以使用基本的FieldPanel
,它提供了整个应用程序可用页面的下拉列表,从那里我们可以自定义该字段的查询更简单。 - 如果您想对此进行更多控制并希望保留模态界面,您可以考虑使用 Wagtail Generic Chooser。
例子
- 下面我们将创建一个自定义
FieldPanel
来修改其on_form_bound
的行为,一旦表单可用,就会在为编辑器构建表单时调用它。 - 从这里我们可以找到该页面列表字段的字段,并将其查询集修改为所需的结果。
page = self.page
将在您未使用InlinePanel
时工作,因为实例将是当前编辑的页面。- 但是,对于
InlinePanel
,我们需要考虑准备作为模板的 'initial' 表单的情况,以便您可以动态添加项目。 - 为了处理
InlinePanel
和基本字段的使用,我们可以获取绑定到自定义面板实例的当前请求,并从那里推断页面。 - 一旦我们有权访问
Page
和字段,我们就可以修改查询集以满足我们的需要,Wagtail 扩展了查询集的能力以添加child_of
andsibling_of
.
some-app/models.py
from wagtail.admin.edit_handlers import FieldPanel
class SiblingOnlyPageFieldPanel(FieldPanel):
def on_form_bound(self):
super().on_form_bound()
field = self.form[self.field_name].field
# when creating a new page, check for the parent page ID & refine field queryset
parent_page_id = self.request.resolver_match.kwargs.get("parent_page_id", None)
if parent_page_id:
parent_page = Page.objects.filter(pk=parent_page_id).first()
field.queryset = field.queryset.child_of(parent_page)
return
# when editing a page, get the ID of the page currently being edited
page_id = self.request.resolver_match.kwargs.get("page_id", None)
if not page_id:
return
page = Page.objects.filter(pk=page_id).first()
if not page:
return
field = self.form[self.field_name].field
field.queryset = field.queryset.sibling_of(page)
class StoryPath(models.Model):
route = models.ForeignKey('story.StoryPage', on_delete=models.SET_NULL, null=True, related_name='next_path', verbose_name='Story Path')
panels = [
SibingOnlyPageFieldPanel('route'), # replaced PageChooserPanel & removed `page_type` as that will no longer work for a normal FieldPanel
FieldPanel('correct'),
]
class Meta:
abstract = True