【问题标题】:How to override template "folder_full_view_item.pt" only for a Custom Type?如何仅针对自定义类型覆盖模板“folder_full_view_item.pt”?
【发布时间】:2014-02-23 05:03:58
【问题描述】:

这个问题以一种令人困惑的方式演变。但是,它的某些部分,特别是一些答案,可能对某人有用。因此,我将不修改此问题,并尝试重新表述问题here


z3c.jbot 覆盖模板folder_full_view_item.pt 将覆盖所有内容类型的模板。 如何在具有多种类型的产品中仅针对单个内容类型 MyType 覆盖它?

具有以下结构:

Folder (layout=folder_full_view)
    Document (layout=document_view)
    MyType (layout=mytype_view)

Plone 中的默认步骤是:

  1. 模板folder_full_view.pt通过item.getObject().folder_full_view_item()调用folder_full_view_item.pt
  2. Products.CMFPlone 的模板folder_full_view_item.pt 添加了不同的ViewletManager(在contenttitle 上方等),并通过use-macro="item_macro" 调用item 的布局。
  3. 包含项目的模板(document_viewmytype_view 等)。

我需要的是一种覆盖模板folder_full_view_item.pt 的方法。在第 2 步中调用覆盖模板 folder_full_view_item.pt 用于 MyType 和 Plone 的 folder_full_view_item.pt 用于所有其他内容类型。

更新

似乎无法覆盖模板folder_full_view_item.pt(不使用jbot)。模板folder_full_view.pt 中的调用item.getObject().folder_full_view_item() 似乎也没有通过“queryMultiAdapter”。

我在这里展示了重现它的所有步骤,并确认 folder_full_view_item 被忽略:

如有必要,设置PLONE_HOME 路径并删除现有的exaple.theme

PLONE_HOME=/path/to/Plone-4.3.2
cd ${PLONE_HOME}/zeocluster/src
rm -rf ${PLONE_HOME}/zeocluster/src/example.theme
sed -i '/example\.theme/d' ${PLONE_HOME}/zeocluster/buildout.cfg

使用develop.cfg 运行构建:

sudo -u plone_buildout ${PLONE_HOME}/zeocluster/bin/buildout -c ${PLONE_HOME}/zeocluster/develop.cfg
cd ${PLONE_HOME}/zeocluster/src
rm -rf /home/Plone-4.3.2/zeocluster/src/example.theme
sudo -u plone_buildout ${PLONE_HOME}/zeocluster/bin/paster create \
        --no-interactive \
        --overwrite \
        -o ${PLONE_HOME}/zeocluster/src \
        -t plone3_theme example.theme \
        expert_mode=all \
        namespace_package=example \
        package=theme \
        skinname='ExampleTheme' \
        skinbase='Sunburst Theme' \
        empty_styles=False \
        include_doc=True \
        version=1.0 \
        description='An installable theme for Plone 3' \
        add_profile=True \
        long_description= \
        author= \
        author_email= \
        keywords='web zope plone theme' \
        url='http://svn.plone.org/svn/collective/' \
        license_name=GPL \
        zip_safe=False \
        zope2product=True

example.theme 添加到构建中:

sed -i '79i\ \ \ \ example.theme' ${PLONE_HOME}/zeocluster/buildout.cfg
sed -i '102i\ \ \ \ src/example.theme' ${PLONE_HOME}/zeocluster/buildout.cfg

注册browser:pages

cat << EOF > ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/configure.zcml
<configure
    xmlns:browser="http://namespaces.zope.org/browser"
    xmlns="http://namespaces.zope.org/zope"
    xmlns:five="http://namespaces.zope.org/five"
    xmlns:cmf="http://namespaces.zope.org/cmf"
    xmlns:i18n="http://namespaces.zope.org/i18n"
    i18n_domain="example.theme">

  <five:registerPackage package="." initialize=".initialize" />
  <include package=".browser" />
  <include file="skins.zcml" />
  <include file="profiles.zcml" />
  <i18n:registerTranslations directory="locales" />

  <browser:page
     for="*"
     name="folder_full_view_item"
     template="folder_full_view_item.pt"
     layer="example.theme.browser.interfaces.IThemeSpecific"
     permission="zope2.View"
     />

  <browser:page
     for="Products.ATContentTypes.content.folder.ATFolder"
     name="folder_full_view"
     template="folder_full_view.pt"
     layer="example.theme.browser.interfaces.IThemeSpecific"
     permission="zope2.View"
     />

  <browser:page
     for="Products.ATContentTypes.content.document.ATDocument"
     name="document_view"
     template="document_view.pt"
     layer="example.theme.browser.interfaces.IThemeSpecific"
     permission="zope2.View"
     />

</configure>
EOF

将原始文件(document_view.ptfolder_full_view.ptfolder_full_view_item.pt)复制到主题:

cp -f ${PLONE_HOME}/buildout-cache/eggs/Products.CMFPlone-4.3.2-py2.7.egg/Products/CMFPlone/skins/plone_content/document_view.pt \
    ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/document_view.pt
cp -f ${PLONE_HOME}/buildout-cache/eggs/Products.CMFPlone-4.3.2-py2.7.egg/Products/CMFPlone/skins/plone_content/folder_full_view_item.pt \
    ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/folder_full_view_item.pt
cp -f ${PLONE_HOME}/buildout-cache/eggs/Products.CMFPlone-4.3.2-py2.7.egg/Products/CMFPlone/skins/plone_content/folder_full_view.pt \
    ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/folder_full_view.pt

稍微修改覆盖的模板以识别它们:

sed -i '/<metal:content-core define-macro="content-core">/a overriden template at '${PLONE_HOME}'/zeocluster/src/example.theme/example/theme/document_view.pt' \
    ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/document_view.pt
sed -i '/<metal:entries fill-slot="entries">/a overriden template at '${PLONE_HOME}'/zeocluster/src/example.theme/example/theme/folder_full_view.pt' \
    ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/folder_full_view.pt
sed -i '/<div tal:replace="structure provider:plone.abovecontenttitle" \/>/i overriden template at '${PLONE_HOME}'/zeocluster/src/example.theme/example/theme/folder_full_view_item.pt' \
    ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/folder_full_view_item.pt
chown -R plone_buildout example.theme

运行 buildout 并启动 plone:

sudo -u plone_buildout ${PLONE_HOME}/zeocluster/bin/buildout -c ${PLONE_HOME}/zeocluster/develop.cfg
${PLONE_HOME}/zeocluster/bin/zeoserver restart
${PLONE_HOME}/zeocluster/bin/client1 fg

如果您想以编程方式创建测试数据(例如来自 ipython),那么您可以执行以下操作:

utils.sync()
plone_site_name = 'Plone'
# delete 'Plone' site if existing
if app.hasObject(plone_site_name): app.manage_delObjects(plone_site_name)
from Products.CMFPlone.factory import addPloneSite
# create 'Plone' site
plone_site = addPloneSite(
                        app,
                        plone_site_name,
                        profile_id=('Products.CMFPlone:plone',),
                        extension_ids=('plonetheme.classic:default',
                                        'plonetheme.sunburst:default',),
                        setup_content=False,
                    )
plone_site = app[plone_site_name]
# install 'plone.app.theming' and 'example.theme'
plone_site.portal_quickinstaller.installProduct('plone.app.theming')
plone_site.portal_quickinstaller.installProduct('example.theme')
# create some content
plone_site.invokeFactory('Document', 'document')
folder_id = plone_site.invokeFactory('Folder', 'folder')
plone_site[folder_id].setLayout('folder_full_view')
plone_site[folder_id].invokeFactory('Document', 'document')
utils.commit()

更新 2

按照建议添加以下内容也不起作用:

从 zope.interface.Interface 定义一个子类:

cat << EOF >> ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/browser/interfaces.py
from zope.interface import Interface
class IMyLayer(Interface):
    """ """
EOF

将其注册为浏览器层:

cat << EOF > ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/profiles/default/browserlayer.xml
<?xml version="1.0"?>
<layers>
  <layer name="imylayer" interface="example.theme.browser.interfaces.IMyLayer" />
</layers>
EOF

为此层注册浏览器:页面:

sed -i 's/layer="example.theme.browser.interfaces.IThemeSpecific"/layer="example.theme.browser.interfaces.IMyLayer"/' \
    ${PLONE_HOME}/zeocluster/src/example.theme/example/theme/configure.zcml

更新 3

item.getObject().folder_full_view_item() 的调用似乎没有通过“常规”层!

我已经用上面的例子测试了以下内容:

folder_full_view 中,将调用item.getObject().folder_full_view_item() 替换为item.getObject().document_view()

修改原来的document_view.pt

echo "original document_view" > ${PLONE_HOME}/buildout-cache/eggs/Products.CMFPlone-4.3.2-py2.7.egg/Products/CMFPlone/skins/plone_content/document_view.pt

修改document_view.pt中的example.theme

echo "overriden document_view" > /home/Plone-4.3.2/zeocluster/src/example.theme/example/theme/document_view.pt

调用文档使用覆盖的document_view.pt

curl -s 'http://localhost:8080/Plone/document' | grep "document_view"
overriden document_view

但调用文件夹(其中包含文档)使用原始的document_view.pt

curl -s 'http://localhost:8080/Plone/folder' | grep "document_view"
original document_view

因此,中心问题似乎是:

是否通过“通常的”发布/图层流程在模板中调用 item.getObject().template_name()

如果没有,如何从folder_full_view 中调用folder_full_view_item 之类的模板并使其通过“通常”的发布/图层流程?

有人可以提示 zope/plone 的哪个部分负责这个“发布/分层过程”吗?

【问题讨论】:

    标签: templates plone overriding theming


    【解决方案1】:

    而不是覆盖folder_full_view_item.pt,您应该将create your own custom default template 用作您的内容类型MyType

    【讨论】:

    • 其实我需要的是覆盖folder_full_view_item。我希望 MyType 在选择了布局 folder_full_view 的封闭文件夹中显示其自己的视图/模板。封闭文件夹的folder_full_view 调用“item.getObject().folder_full_view_item()”,后者又调用MyType 的模板。 folder_full_view_item 不仅调用了 MyType 的模板,而且还添加了一些我不需要的额外元素。
    【解决方案2】:

    要覆盖此模板,您需要两件事:浏览器层和将在您的内容类型的上下文中使用的视图。

    首先,声明浏览器层:

    from zope.interface import Interface
    
    class IMyLayer(Interface):
        """A layer specific for this add-on product.
        """
    

    此浏览器层需要与您的内容类型一起安装。使用以下内容创建 browserlayer.xml 文件:

    <?xml version="1.0"?>
    <layers>
      <layer name="my.type" interface="my.type.interfaces.IMyLayer" />
    </layers>
    

    然后,当您处于内容类型的上下文中并且您的浏览器层处于活动状态时,视图将处于活动状态:

    from five import grok
    
    class FolderFullViewItem(grok.View):
        """Override folder_full_view_item for MyType.
        """
        grok.context(IMyType)
        grok.layer(IMyLayer)
        grok.name('folder_full_view_item')
        grok.template('folder_full_view_item')
        grok.require('zope2.View')
    

    sc.blog 上,我们有一个类似的用例,我们覆盖了 folder_summary_viewfolder_full_view,看看它。

    另外,不要忘记阅读 Plone 开发者文档中的 Layers 章节。

    【讨论】:

    • 我确实想覆盖 folder_full_view_item.pt,而不是folder_full_view.pt。在您提到的示例sc.blog 中,您只需覆盖调用Plone 的folder_full_view_item.ptfolder_full_view.pt。我知道我可以用MyType 覆盖folder_full_view.pt 并调用另一个模板而不是folder_full_view_item.pt 但这不是我要问的。请仔细阅读我的问题。
    • 如果您仔细阅读我的回答,您会注意到 grok.context(IMyType) 完成了这项工作。
    • 你介意解开你的答案吗?我们的项目很简单
    • 看来template folder_full_view_item.pt 不能被覆盖(不使用jbot!)。模板folder_full_view.pt 中的调用item.getObject().folder_full_view_item() 甚至似乎不是通过“queryMultiAdapter”的情况。查看我的问题更新。
    • Hector,您的回答适用于要覆盖的所有其他模板。但不幸的是它不适用于模板folder_full_view_item.pt。还是我误解了整个图层的问题?
    【解决方案3】:

    尝试使用tal:condition="python:item_type=='MyType'"item_type!='MyType' 来满足不同的显示需求。希望这会有所帮助。

    【讨论】:

    • 我确实想覆盖 folder_full_view_item.pt。请仔细阅读问题。
    【解决方案4】:

    由于皮肤工具似乎已被弃用并且可能会涉及性能损失,我宁愿也为您的自定义内容类型使用专用的浏览器视图,但要回答这个问题:

    您可以使用collective.editskinswitcher(感谢 M. v. Rees!),而无需重写太多,甚至可以在此过程中获得一些不错且易于配置的开发功能(访问者查看,实际登录时,通过 URL 区分,例如)。

    在这种情况下,我们利用在文件夹内容类型对象上设置皮肤属性的可能性,大致而言,这些步骤应该可以达成交易:

    • 将自定义的folder_full_view_item.pt - 模板放置在您主题的任何皮肤文件夹中。

    • 在创建你的内容类型时,添加一个事件监听器,它将新生成的对象的 skin_name 设置为你的主题的皮肤名称(查看 c.editskinswitcher 的方法和道具,引用 HTTP-请求是@@switchDefaultSkin?skin_name=YourTheme,顺便说一句)。

    • 将另一个主题皮肤设置为 portal_skins-properties 中所有其他上下文的全局默认设置。

    【讨论】:

    • 非常感谢您的回答!这正是我们现在正在使用的:我们使用collective.editskinswitcher 切换的主题/皮肤的组合。确实,感谢 Maurits!但是,除了这种与图书馆(和文档!)的杂耍和斗争有时会变成一个真正的皮塔饼,我实际上并且真的对我的问题的答案非常感兴趣:(1)是否可以覆盖@ 987654327@ 正如大多数人(突然)建议的那样? (2) 除了通过item.getObject().folder_full_view_item() 之外,还有其他方法可以调用此模板吗?
    • 另一方面,我非常感谢 plone 开发人员就“不推荐使用”、“老式”、“老式”等库/工具的明确声明?但是这个论坛真的不是抱怨这个的地方;-)即使我非常感谢你的努力@ida-ebkes,它也没有回答我的问题。
    • 这个任务已经成长为一部小说(又名 tl;dr),并且现在已经上升了几个点。关于您的评论(1):到目前为止,这已经以多种方式得到了回答,请随时通过投票表示您的赞赏(我做到了)。关于(2):总有办法;)但也许你想用这个特定的点打开一个新的任务。关于第二条评论中的咆哮:Skins-tool 肯定会被弃用,但在告别的时间终于到来之前,还有一些事情要做。正如您所建议的那样,它可能应该得到更好的记录和讨论,这引发了下一个任务:
    • 在哪里讨论?传统上这发生在邮件列表中,然后 SO 被包含为支持选项,现在我们有 community.plone.org 但还没有正式的切换。所以,我在这里再次询问:plone.293351.n2.nabble.com/… 关于当前的通信通道状态。
    • 总结这个任务:不,你不能让皮肤模板的行为与浏览器视图完全一样,很明显。但是,您可以通过各种更好的方式解决您的用例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    • 2019-08-01
    • 2016-01-16
    • 2017-07-17
    相关资源
    最近更新 更多