Wagtail开发:如何基于同一页面模型适配不同Bokeh图表模板
简化Wagtail+Bokeh页面结构的方案
1. 核心方案:单页面模型+可选择的Bokeh标签
给页面模型新增选择字段,让CMS后台编辑能直接选择要调用的Bokeh模板标签,再通过通用模板根据选择动态渲染内容,完全省去多模型多模板的冗余。
修改页面模型
from wagtail.models import Page from django.db import models class BokehPage(Page): # 保留原有文本字段,比如页面正文 body = models.TextField() # 添加Bokeh标签选择器 bokeh_tag = models.CharField( max_length=20, choices=[ ('bokehgraph', 'Bokeh图表1'), ('bokehgraph2', 'Bokeh图表2'), ], default='bokehgraph', verbose_name='选择Bokeh图表类型' ) content_panels = Page.content_panels + [ models.FieldPanel('body'), models.FieldPanel('bokeh_tag'), ]
通用模板(bokeh_page.html)
模板中根据模型的选择值,加载对应的自定义标签:
{% extends "base.html" %} {% load your_bokeh_tags %} <!-- 替换成你的自定义标签库名称 --> {% block content %} <div class="page-content"> {{ page.body|safe }} <div class="bokeh-wrapper"> {% if page.bokeh_tag == 'bokehgraph' %} {% bokehgraph %} {% elif page.bokeh_tag == 'bokehgraph2' %} {% bokehgraph2 %} {% endif %} </div> </div> {% endblock %}
后续新增Bokeh标签时,只需要给bokeh_tag的choices加选项,模板里补对应的判断即可,不用动模型和模板结构。
2. 进阶方案:用StreamField实现自由内容组合
如果需要更灵活的页面布局(比如文本和图表穿插、多图表组合),可以利用Wagtail的StreamField定义可复用的Bokeh组件:
定义StreamBlock
from wagtail.fields import StreamField from wagtail.blocks import StructBlock, TextBlock, ChoiceBlock class BokehGraphBlock(StructBlock): graph_type = ChoiceBlock( choices=[ ('bokehgraph', '图表1'), ('bokehgraph2', '图表2'), ], required=True ) class Meta: template = 'blocks/bokeh_graph_block.html' icon = 'graph' class FlexibleBokehPage(Page): body = StreamField([ ('text', TextBlock()), ('bokeh_graph', BokehGraphBlock()), ], use_json_field=True) content_panels = Page.content_panels + [ models.FieldPanel('body'), ]
组件模板(blocks/bokeh_graph_block.html)
{% load your_bokeh_tags %} <div class="bokeh-block"> {% if self.graph_type == 'bokehgraph' %} {% bokehgraph %} {% elif self.graph_type == 'bokehgraph2' %} {% bokehgraph2 %} {% endif %} </div>
这种方式让编辑能在页面里自由添加文本块和不同类型的Bokeh图表,完全不需要新增模型或模板,扩展性拉满。
3. 额外优化:模板标签参数化
如果Bokeh标签需要动态参数(比如不同数据源),可以给模型加参数字段,再在模板里传递给标签:
# 模型新增参数字段 bokeh_data_key = models.CharField(max_length=50, blank=True, verbose_name='数据源标识') # 模板传递参数 {% if page.bokeh_tag == 'bokehgraph' %} {% bokehgraph page.bokeh_data_key %} {% elif page.bokeh_tag == 'bokehgraph2' %} {% bokehgraph2 page.bokeh_data_key %} {% endif %}
这样同一个标签能根据参数渲染不同内容,进一步减少重复代码。
内容的提问来源于stack exchange,提问作者John Moody
相关产品推荐
相关产品推荐

